HAVING mi WHERE mi? SQL'de Satır ve Grup Filtrelemenin Farkı
WHERE satırları gruplamadan önce, HAVING grupları toplama işleminden sonra süzer. Örnek sorgular, çalışma sırası, sık hatalar ve performans ipuçları.
Tek cümlelik fark
WHERE, tablodan gelen satırları gruplama ve toplama (aggregate) işlemlerinden önce süzer; hangi satırların hesaplamaya gireceğini belirler. HAVING ise GROUP BY ile oluşan grupları, toplama fonksiyonları hesaplandıktan sonra süzer; hangi grupların sonuçta görüneceğini belirler.
PostgreSQL belgelerinin ifadesiyle temel fark şudur: WHERE girdi satırlarını gruplar ve toplamlar hesaplanmadan önce seçer, HAVING ise grup satırlarını gruplar ve toplamlar hesaplandıktan sonra seçer. Bu yüzden WHERE koşulunda SUM, COUNT, AVG gibi toplama fonksiyonları kullanılamaz; HAVING koşulu ise tipik olarak bu fonksiyonları içerir.
Pratik kural: Koşul tek bir satırın değerine bakıyorsa WHERE, bir grubun toplu sonucuna bakıyorsa HAVING kullanılır.
Sorgunun mantıksal çalışma sırası
Farkı kavramanın en kolay yolu, bir SELECT sorgusunun mantıksal olarak hangi sırayla değerlendirildiğini bilmektir. Yazım sırası farklı olsa da veritabanı sorguyu kavramsal olarak şu sırayla işler:
- FROM ve JOIN: Kaynak tablolar okunur ve birleştirilir.
- WHERE: Satırlar tek tek süzülür.
- GROUP BY: Kalan satırlar gruplara ayrılır.
- Toplama fonksiyonları: Her grup için SUM, COUNT, AVG gibi değerler hesaplanır.
- HAVING: Gruplar süzülür.
- SELECT: Sonuç sütunları ve takma adlar (alias) oluşturulur.
- ORDER BY: Sonuç sıralanır.
Bu sıra iki önemli sonucu açıklar. WHERE çalıştığında henüz grup ve toplam olmadığı için toplama fonksiyonuna başvuramaz. HAVING ise toplamlar hesaplandıktan sonra çalıştığı için bunlara erişebilir. Veritabanı motorları performans için işlemleri farklı bir fiziksel sırayla da yürütebilir, ama sonuç bu mantıksal sıraya uygun olmak zorundadır.
Ölçüt ölçüt HAVING ve WHERE
- Neyi süzer: HAVING / GROUP BY ile oluşan grupları. WHERE / tablodaki tekil satırları.
- Ne zaman çalışır: HAVING / gruplama ve toplama işleminden sonra. WHERE / gruplama ve toplama işleminden önce.
- Toplama fonksiyonu: HAVING / kullanılabilir ve tipik kullanımı budur. WHERE / kullanılamaz; kullanılırsa veritabanı hata verir.
- GROUP BY ile ilişkisi: HAVING / genellikle GROUP BY ile birlikte kullanılır; GROUP BY olmadan yazılırsa tüm tablo tek bir grup kabul edilir. WHERE / GROUP BY olsun olmasın kullanılabilir.
- Kullanıldığı komutlar: HAVING / SELECT sorguları. WHERE / SELECT, UPDATE ve DELETE komutları.
- Performans etkisi: HAVING / gruplama sonrası çalıştığı için, satır düzeyinde yazılabilecek bir koşul burada yazılırsa gereksiz satırlar da gruplanır. WHERE / erken süzme sayesinde gruplanacak ve okunacak veri miktarını azaltır; uygun indeks varsa kullanabilir.
- Yazım yeri: HAVING / GROUP BY'dan sonra, ORDER BY'dan önce. WHERE / FROM ve JOIN'den sonra, GROUP BY'dan önce.
Birlikte kullanım: Adım adım örnek
Örneğin bir siparisler tablosunda her siparişin şehri, durumu ve tutarı tutuluyor. İstenen rapor: Yalnızca teslim edilmiş siparişler dikkate alınarak, toplam cirosu belirli bir hedefin üzerinde kalan şehirler.
SELECT sehir, SUM(tutar) AS toplam_ciro FROM siparisler WHERE durum = 'TESLIM_EDILDI' GROUP BY sehir HAVING SUM(tutar) > :hedef_ciro ORDER BY toplam_ciro DESC;
Sorgu şöyle işler: WHERE iptal edilen ve iade edilen siparişleri en baştan dışarıda bırakır. GROUP BY kalan satırları şehirlere ayırır. SUM her şehrin cirosunu hesaplar. HAVING, cirosu hedefin altında kalan şehirleri sonuçtan çıkarır. Son olarak sonuç ciroya göre sıralanır.
Buradaki :hedef_ciro bir parametredir; uygulama ya da raporlama aracı sorguyu çalıştırırken değeri yerine koyar. Aynı mantık "belirli sayıdan fazla siparişi olan müşteriler" için HAVING COUNT(*) > :asgari_siparis biçiminde kurulur.
Sık yapılan hatalar
- Toplama fonksiyonunu WHERE'de kullanmak: WHERE SUM(tutar) > :hedef_ciro gibi bir koşul hata verir. Toplam üzerinden süzme HAVING'e yazılmalıdır.
- Satır koşulunu HAVING'e yazmak: sehir bir gruplama sütunu olduğu için HAVING sehir = 'İzmir' koşulu çalışır, ama gereksiz yere tüm şehirler gruplandıktan sonra süzme yapar. Bu koşul WHERE'e taşınmalıdır.
- SELECT'teki takma adı WHERE'de kullanmak: SELECT tutar * kdv_orani AS brut ... WHERE brut > :esik ifadesi standart SQL'de çalışmaz, çünkü WHERE, SELECT'ten önce değerlendirilir. İfadeyi WHERE içinde tekrar yazmak ya da alt sorgu veya CTE kullanmak gerekir.
- HAVING'de takma ada güvenmek: Bazı veritabanları HAVING içinde SELECT takma adına izin verir, bazıları vermez. Taşınabilir sorgu için toplama ifadesini HAVING içinde açıkça yazmak daha güvenlidir.
- NULL değerleri unutmak: WHERE durum <> 'IPTAL' koşulu, durumu NULL olan satırları da dışarıda bırakır. NULL'ların nasıl ele alınacağı ayrıca düşünülmelidir.
Alternatifler: Alt sorgu, CTE ve pencere fonksiyonları
HAVING tek seçenek değildir. Aynı sonuç, gruplanmış sonucu bir alt sorguya ya da CTE'ye (WITH ifadesi) koyup dış sorguda WHERE ile süzerek de elde edilebilir:
WITH sehir_ciro AS ( SELECT sehir, SUM(tutar) AS toplam_ciro FROM siparisler WHERE durum = 'TESLIM_EDILDI' GROUP BY sehir ) SELECT sehir, toplam_ciro FROM sehir_ciro WHERE toplam_ciro > :hedef_ciro;
Bu yazım, ara sonucun birden fazla yerde kullanıldığı ya da koşulların karmaşıklaştığı sorgularda okunabilirliği artırır. Pencere fonksiyonları (OVER ifadesi) ise satırları gruplayıp azaltmadan her satırın yanına grup toplamını ekler; "her siparişi, ait olduğu şehrin toplam cirosuyla birlikte göster" gibi ihtiyaçlarda HAVING yerine kullanılır. Pencere fonksiyonunun sonucu doğrudan WHERE'de kullanılamaz; bunun için de alt sorgu ya da CTE gerekir.
Mindset SQL eğitimlerinde bu konu
SQL ile Veri Sorgulama (Temel) eğitiminde filtreleme teknikleri ile toplulaştırma fonksiyonları ve gruplama ayrı modüller olarak ele alınır; pratik iş raporları modülü bu iki aşamanın birlikte kullanıldığı sorgulara odaklanır. SQL ile Programlama Eğitimi'nde sorgular ile toplama ve gruplama modülleri aynı konuyu kapsar.
SQL ile Veri Sorgulama (İleri) eğitimi CTE, alt sorgular ve pencere fonksiyonlarıyla HAVING'in alternatiflerini işler. LLM ile Veri Sorgulama (Text-to-SQL) eğitimi ise dil modellerinin ürettiği sorguların doğrulanmasını ele alır; WHERE ile HAVING'in karıştırılması bu doğrulamada kontrol edilen tipik hatalardandır.
İlgili Mindset programı
SQL ile Veri Sorgulama (Temel)
Sık sorulan sorular
HAVING, GROUP BY olmadan kullanılabilir mi?
Kullanılabilir. Bu durumda tüm sonuç kümesi tek bir grup kabul edilir ve HAVING bu tek grubun toplam değerine göre ya tek satır döner ya da hiç satır dönmez. Örneğin tablodaki toplam ciro bir eşiğin üzerindeyse sonuç gösterilir. Pratikte seyrek kullanılır.
Aynı sorguda hem WHERE hem HAVING olabilir mi?
Evet, sık kullanılan bir yapıdır. WHERE önce satır düzeyindeki koşulları uygular, gruplama ve toplama bu süzülmüş satırlar üzerinde yapılır, ardından HAVING toplam değerlere göre grupları süzer. Satır koşullarını WHERE'de, toplam koşullarını HAVING'de tutmak sorguyu hem doğru hem de verimli kılar.
HAVING ile WHERE arasında performans farkı var mı?
Koşulun türüne bağlıdır. Satır düzeyinde bir koşul WHERE'e yazıldığında veri gruplanmadan önce azalır ve uygun indeks kullanılabilir. Aynı koşul HAVING'e yazıldığında tüm satırlar gruplanır, ardından süzülür. Bazı veritabanı optimizasyon motorları bu tür koşulları otomatik olarak öne taşıyabilir, ancak buna güvenmek yerine koşulu doğru yere yazmak gerekir.
HAVING'de toplama fonksiyonu olmayan bir koşul yazılabilir mi?
Yazılabilir; GROUP BY'da yer alan bir sütun üzerinden koşul HAVING'de de çalışır. PostgreSQL belgeleri bunun teknik olarak mümkün olduğunu ama nadiren işe yaradığını, aynı koşulun WHERE aşamasında daha verimli uygulanabileceğini belirtir.
HAVING'de bir sütunu kullanınca neden "GROUP BY'da olmalı" hatası alınır?
Çünkü HAVING grup satırları üzerinde çalışır ve her gruptan tek bir değer bekler. Koşulda geçen sütun ya GROUP BY listesinde olmalı ya da SUM, MAX gibi bir toplama fonksiyonunun içinde kullanılmalıdır. Gruba ait olmayan bir sütunun hangi satırdan alınacağı belirsiz olduğu için veritabanı sorguyu reddeder.
İlgili rehberler
İlgili eğitimler
Kategori: Veri Analitiği ve İş Zekası