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.