Select, Group By, Having

Merhabalar,

Bu yazı, bir önceki SQL nedir, ne deÄŸildir ? adlı yazının devamı ÅŸeklinde olacak ve ‘Group By’ ve ‘Having’ ile SELECT sonuçu olarak dönen liste üzerinde yapılan iÅŸlemlere deÄŸineceÄŸiz.

Geçen yazımızdan hatırlayacağınız gibi, SELECT cümlesi geriye bir liste dönen bir ve üç ana parçaya ayırabileceğimiz bir komut idi. Bu ana parçalardan kısaca bahsedecek olursak;
– süzme iÅŸlemi (WHERE alt cümlesi ile yapılabilen)
– sıralama iÅŸlemi (ORDER BY alt cümlesi ile yapılabilen)
– geri dönen liste üzerinde yapılan iÅŸlemler (GROUP BY, HAVING, MAX, SUM, COUNT, MIN….vs.)

Peki SELECT cümlesinde gerçekleşen olayları biraz daha derinden inceleyelim, bu şekilde GROUP BY ve diğer işlemlerin anlaşılmasını kolaylaştırmaya çalışalım.

SELECT Price
  FROM Customer
 WHERE Price < 100
   AND Price > 50

Bu SQL cümlesinden geriye bir liste gelir, buraya kadar herşey çok normal ve oldukça basit. Ama biz biraz daha analitik bir liste istersek ki iş dünyasında bu çeşit listelere oldukça fazla başvuruluyor.

  SELECT Count(*), Price
    FROM Customer
   WHERE Price < 100
     AND Price > 50
GROUP BY Price

Yukarıdaki cümlede durum biraz karışık ama inanın göründüğü kadar deÄŸil, şöyleki; Bu SELECT cümlesi bir üstte belirtiÄŸimiz SELECT cümlesi ile aynı listeyi oluÅŸturur ama son yazılan SELECT cümlesine ‘Count(*)’ ve ‘GRUOP BY’ gibi SELECT’den dönen listeyi deÄŸiÅŸtiren alt cümleleri eklenmiÅŸtir. Biz standart listeleme iÅŸleminden dönen (yani Price bilgisi 100 ile 50 arasında olan Customer listesine) listeye düşük seviyeli liste diyelim. Bu düşük seviyeli listenin üzerine GRUOP BY ve COUNT iÅŸlemleri uygulandıktan sonra ortaya çıkan yeni listeye ise sonuç listesi adını verelim.

Veri tabanı uygulamaları, işte bu mantık doğrultusunda öncelikle düşük seviyeli listeleri oluşturur ve bu düşük seviyeli listeler üzerine yapılan işlemlerle sonuç listesini meydana getirirler. Bu bilgiler ışığında GROUP BY alt cümlesinin tanımı şu şekilde olabilir;
– Cümleden sonra parametre olarak belirtilen alanın veya alanların deÄŸerine göre düşük seviyeli listeyi parçalara ayırır, belirtilen alanın veya alanların kaç farklı deÄŸeri var ise o kadar düşük seviyeli liste oluÅŸturur.

Bu tanım biraz daha aklınıza yattı değil mi.. ?

Peki şimdi bir de COUNT(*), MIN, MAX, AVERAGE gibi fonksiyonların nasıl çalıştıklarını anlatmaya çalışalım;
– Tüm bu fonksiyonlar, düşük seviyeli listenin tamamı üzerine çalışır. EÄŸer düşük seviyeli liste GRUOP BY ile bölünmüş ise, her bir parça için ayrı ayrı çalışırlar.

Yani son SQL cümlesinde yer alan Count(*) işlemi her Price değeri için bölünmüş olan düşük seviyeli listenin herbir parçası için çalışır. Ve ortaya sonuç listesi olarak, her parçanın içerisinde yer alan kayıt sayısı ve her parçanın ayıraçı konumundaki Price bilgisi çıkar. Örnek;

Count(*) - Price
    5            60
    7            70
... vb.

Peki biz şu şekilde bir SQL cümlesi yazacak olursak;

  SELECT Count(*), Price, Name
    FROM Customer
   WHERE Price < 100
     AND Price > 50
GROUP BY Price

Veri tabanı bize hata verecektir. Hemen aklınızdan ‘KardeÅŸimmmm bu ne hatası böyleee…. eee Customer üzerinde Name var.. neden görmez bunu bu salak..’ vb. düşünceler geçebilir. Aman geçmesin çünkü veri tabanı manyağı haklı. Peki neden haklı onu inceleyelim;

Şimdi öncelikle düşük seviyeli listenin ne olduğunu bulalım;
– Price bilgisi 100 ile 50 arasında olan Customer bilgileri.. Id, Price, Name…vs.. vs.. Bu listeye ‘A’ listesi diyelim.

‘GRUOP BY’ iÅŸlemi olduÄŸuna göre, elimizdeki düşük seviyeli ‘A’ listesi Price bilgisinin deÄŸerlerine göre bölümlere ayrılmıştır. Örnek olarak Price bilgisi 5 farklı deÄŸere sahip olsun elimizdeki ‘A’ listesi ‘A1, A2, A3, A4, A5’ ÅŸeklinde küçük listelere ayrılır.

Daha sonra COUNT(*) iÅŸlemi ile bu her bir küçük listenin adet bilgisi ile Price ve Name bilgisi sonuç listesine verilmiÅŸtir. Peki burada ki gariplik ne, neden hata veriyor. Sorun ÅŸu A listesinden A1’e geçiÅŸ sırasında her bir Price’a karşılık ‘n’ adet Name bilgisi oluÅŸmuÅŸtur bu nedenle sonuç listesi oluÅŸturulurken, Count bilgisi hesaplanmış, Price bilgisi tek olduÄŸu için alınmış fakat hangi Name bilgisinin kullanılacağına karar verilememiÅŸtir.

Düşük Seviyeli Liste’nin son hali..

Id Price Name
1 60 Test60-1
2 60 Test60-2
3 70 Test70-1
4 70 Test70-2
5 80 Test80-1
6 90 Test90-1

‘Group By’ uygulandıktan sonraki düşük seviyeli listenin hali;

Price Alt Kümeler
60
Id Name
1 Test60-1
2 Test60-2
70
Id Name
1 Test70-1
2 Test70-2
80
Id Name
1 Test80-1
90
Id Name
1 Test90-1

İşte bu da son ipucu; SQL programlama dilinde herhangi bir liste oluşturabilmek için bir kademe altta yer alan listenin elemanları direkt olarak kullanılabilir ya da fonksiyonlar yardımı ile alt listelere ulaşılıp, toplam, en küçük, en büyük, ortalama.. vb. değerler elde edilebilir.

Kolay gelsin.

Select, Group By, Having” üzerine 11 yorum

  1. evet buraya kadar “kolay geldi” gerçekten :)
    ama yazınıza devam etmemenize üzüldüm, sql’e yeni baÅŸladım ve bir kaç sorun yaÅŸadım, bunları araÅŸtırırken buldum sitenizi..
    Yinede çok teşekkürler yazılarınız için, sql yazılarınızı takip ediyo olucam :)

  2. Åžimdi bir resimler tablom var ve bu tabloda kategoriler isimli bir alanım var 17 deÄŸiÅŸik isimde 600 den fazla kayıt var.Ben bu tablodan bu 17 deÄŸiÅŸik kaydı bununla ilgili “bresim” alanından bir resimi ve ilgili kategoride kaç adet resim olduÄŸunu yazdırmak istiyorum.
    Bu işlemin Group by bağlantısı ile yapılabileceğini düşündüğüm için bu konuyu araştırıyorum çeşitli denemeler yapmama rağmen bunu başaramadım.Kategorileri aldım ama resim çekemedim ve adet yazdıramadım.Bir fikir lütfen.

  3. Merhaba Artvinli,

    SELECT kategoriler, max(bresim) as bresim1, count(*) as adet
    FROM resimler
    GROUP BY kategoriler

    bunu deneyip sonucu dönermisin ?

    Bu arada ben de Artvinliyim :).

  4. Yazınız için teşekkurler. Ancak bu konu ile ilgili webde belki binlerce sayfa da zaten bilgi veriliyor. Benim bilen arkadaşlara şöyle bir sorum olacak.
    bir tablom var (evraknosu,tarih,boclu,vs)
    bana her borclunun en yakın(büyük) tarihteki evrak nosunu gösterebilirmisiniz?
    (bir borçlunun birçok değişik tarihde değişik evrak noları ile kayıtları var.)
    Sonuç şöyle olacak Borclu,(max)tarih,evrakno . Her borçlu için tek satır.
    Bu kadar basit bir isteği tek select ifadesi ile yapanın elini öperim.

  5. Merhabalar,

    Geç yanıt için özür dilerim, mail ve blog adreslerimin şifreleri ile ilgili olarak bazı problemler yaşadım da. Eğer borclu ve tarih bilgileri tekil ise çözüm aşağıdaki gibi olabilir. Deneyebilir misin?

    SELECT id, borclu, tarih, evrakno
    FROM tablo_adi
    WHERE (borclu, tarih) IN (SELECT borclu, MIN(tarih)
    FROM tablo_adi
    WHERE tarih > SYSDATE
    GROUP BY borclu)

    * Bu çözüm ORACLE için yazılmıştır. Diğer sunucular için denenmemiştir.

  6. Merhaba hocam sql ye yeni başladım yardımcı olursanız sevinirim,
    Şimdi benim cicek adında tablom var
    burada kime ve kimden alanları var kimden kimeye çiçek gönderiyor :)
    ben en en çok cicek alanları listelemek istiyorm

    Select kime, max(kime), count(*) as adet from cicek group by kime;

    Şöle bişi yaptım ama entresan sonuçlar veriyor
    adet kısmı doğru ama listelemede sorun var :(
    yardımcı olursanıs sevinirim

  7. id kime kimden
    1 50 25
    2 50 125
    3 10 40
    4 50 38
    5 10 36
    6 50 20
    7 50 10
    8 8 78

    istediğim listelenme şeklide şöyle

    1 – 5 – 50
    2 – 2 – 10
    3 – 1 – 8

  8. Merhabalar,

    Sanırım şu şekilde bir sorgu ile çözüme ulaşabilirsin;
    “SELECT COUNT(*), kime FROM cicek GROUP BY kime ORDER BY 1 DESC, kime”
    Umarım yardımcı olabilmişimdir.

  9. Sanırım şu şekilde bir sorgu ile çözüme ulaşabilirsin;
    “SELECT COUNT(*), kime FROM cicek GROUP BY kime ORDER BY 1 DESC, kime”
    Umarım yardımcı olabilmişimdir.

    Tşk ederim yanlız bişeyi eklemeyi unutmuşum

    Members tablosundaki
    id kcinsiyet
    1 0
    2 1
    3 0
    4 0
    5 1

    ————————

    ÅŸu deÄŸiÅŸken ile

    atıyorum
    Session(“kcinsiyet”)=1
    ise

    kcinsiyeti 0 olanların aldığı en çok çiçek sayısını çıkartabilir

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir