3.6. Ortak Değer İşlevleri
Çoğu ilişkisel veritabanı ürünü gibi PostgreSQL'de ortak değer işlevlerini destekler. Bir ortak değer işlevi çok sayıda satırı girdi olarak alır ve bunlardan tek bir sonuç elde eder. Belli bir satır grubu üzerinde işlem yaparak, bunların sayısını bulan count
, değerlerin toplamını bulan sum
, değerlerin ortalamasını hesaplayan avg
, en büyük ve en küçük değerleri bulan max
ve min
işlevleri bunlara birer örnektir.
Örnek olarak, düşük sıcaklık değerlerinin en yükseğini bulalım:
SELECT max(asg_sck) FROM hava_durumu;
Sonuç:
max ----- 46 (1 satır)
Eğer bu sıcaklığın hangi il (veya illerde) ortaya çıktığını bulmak istersek,
SELECT il FROM hava_durumu WHERE asg_sck = max(asg_sck); YANLIŞ
bu çalışmaz, çünkü max
işlevi WHERE
deyiminde kullanılamaz. (Böyle bir sınırlamanın olmasının sebebi, WHERE
deyiminin ortak değeri bulunacak satırların belirlenmesinde kullanılmak zorunda olmasıdır; yani, deyim, işlevden önce değerlendirilmiş olmalıdır.) Bu durumda böyle bir sorunu gidermek için sorgunun yeniden durumlanabilmesini sağlayan aşağıdaki gibi bir altsorgu (subquery) kullanılır:
SELECT il FROM hava_durumu WHERE asg_sck = (SELECT max(asg_sck) FROM hava_durumu);
Sonuç:
il --------------- San Francisco (1 satır)
Şimdi her şey yolunda. Çünkü ortak değer bulma bir altsorgu ile yapıldıktan sonra sonuç dış sorguda karşılaştırma değeri olarak kullanıldı.
Ortak değer işlevleri GROUP BY
deyimi ile kullanıldığında oldukça yararlıdır. Örneğin her şehrin en yüksek düşük sıcaklığını bulmak için şunu yazabiliriz:
SELECT il, max(asg_sck) FROM hava_durumu GROUP BY il;
Bu bize her il için bir değer verecektir:
il | max ---------------+----- Hayward | 37 San Francisco | 46 (2 satır)
Burada, satırlar illere göre gruplanmakta, her gruptaki satırlar üzerinde max
işlevi hesaplanmakta ve sonuçlar listelenmektedir. Hesaplamaya dahil olacak satırları HAVING
deyimini kullanarak gruplayabiliriz:
SELECT il, max(asg_sck), count(*) FILTER (WHERE asg_sck < 30) FROM hava_durumu GROUP BY il HAVING max(asg_sck) < 40;
Çıktısı:
il | max | count ---------+-----+------- Hayward | 37 | 0 (1 satır)
Sadece asg_sck
değeri 40'ın altında olan illeri listelemesi dışında bu cümle de aynı sonucu verir. Eğer bir de bu işi abartıp sadece "S" ile başlayan il isimlerini istersek:
SELECT il, max(asg_sck), count(*) FILTER (WHERE asg_sck < 30) FROM hava_durumu WHERE il LIKE 'S%' -- ❶ GROUP BY il HAVING max(asg_sck) < 40;
- ❶
-
LIKE
işleci kalıp eşleştirmesi yapar ve PostgreSQL belgelerindeki Kalıp Eşleme bölümünde açıklanmıştır.
SQL dilinde WHERE
ve HAVING
deyimlerinin ortak değer işlevleri ile nasıl etkileşime girdiğinin anlaşılması önemlidir. WHERE
ve HAVING
deyimleri arasındaki temel fark şudur: WHERE
satırları, gruplar ve ortak değerler hesaplanmadan önce seçer (ortak değer hesaplamasında kullanılacak satırları seçer), HAVING
deyimi ise ortak değerler hesaplandıktan ve gruplamalar yapıldıktan sonra işleme sokulur. Sonuç olarak, WHERE
ifadelerinde (altsorgu dışında) ortak değer bulma işlemleri kullanılmazken, HAVING
deyimlerinde kaçınılmazdır. (Aslında HAVING
deyimleri içinde ortak değer işlevleri dışında ifadeler de kullanmanıza izin verilmiştir ama, bu biraz savurganlık olur; böyle bir koşulu WHERE
deyiminde kullanmak daha verimlidir.)
Önceki örnekte, WHERE
deyiminde bir ortak değer bulma işlemine ihtiyaç duyulmadığından, il isimlerine kısıtlama uygulamıştık. Bu, kısıtlamanın HAVING
ile sağlanmasından daha uygundur; çünkü gruplamanın ve ortak değer hesaplamasının WHERE
sınamasından geçemeyen satırlar için yapılması gereksizdir.