Harun Reşit Zafer

bâki kalan bu kubbede bir hoş sadâ imiş

SQL 16: HAVING İfadesi

Schema SQL Son iki yazımda SQL kümeleme fonksiyonlarını ve GROUP BY ifadesini anlatmıştım. HAVING ifadesi bu iki yazıda anlatılanların devamı, çünkü sadece GROUP BY ifadesi ile birlikte kullanılan bir ifade. Aslında HAVING ifadesinin işlevi WHERE ifadesininkine çok benziyor. Ancak kümeleme fonksiyonları ile WHERE ifadesi birlikte kullanılamadığından HAVING ifadesine ihtiyaç duyulmuştur. Meseleyi daha iyi izah edebilmek için hemen örneklere geçelim.

Not: Bu arada diğer SQL derslerine buradan ulaşabilirsiniz

Öncelikle bir önceki makalede de kullandığımız aşağıdaki kisiler tablosunu inceleyelim. Sonra bu tablo üzerinden örneklerle konuyu inceleyeceğiz.

id Ad Soyad Yas Cinsiyet Şehir Ülke Maaş
2 Ahmet Yılmaz 20 1 Ankara Türkiye 2000
3 Mehmet Efe 22 1 Bolu Türkiye 2000
4 Ayşe Can 23 0 İstanbul Türkiye 3500
5 Fatma Ak 35 0 Ankara Türkiye 3200
6 John Smith 45 1 New York USA 3500
7 Ellen Smith 40 0 New York USA 3500
8 Hans Müller 30 1 Berlin Almanya 4000
9 Frank Cesanne 35 1 Paris Fransa 3700
10 Abbas Demir 26 1 Adana Türkiye 2000
11 Hatice Topçu 26 0 Hatay Türkiye 2200
12 Gülsüm Demir 35 0 Adana Türkiye 2000

 

Öncelikle aşağıdaki 2 sorgu örneğini inceleyelim:

SELECT ülke, AVG(maaş) FROM `kisiler` GROUP BY ülke

Bu sorgu ülkelere göre maaş ortalamasını verir ve çıktısı aşağıdaki gibidir:

ülke AVG(maaş)
Almanya 4000.0000
Fransa 3700.0000
Türkiye 2414.2857
USA 3500.0000

 

 SELECT ülke, AVG(maaş) FROM `kisiler` WHERE yas > 30 GROUP BY ülke

Dikkat ederseniz bu sorgunun bir öncekinden tek farkı “WHERE yas > 30” kısmı. Sorgu yine ülkelere göre maaş ortalamasını hesaplıyor ama bu hesaba yalnızca yaşı 30’dan büyük olan çalışanları katıyor. Sorgunun çıktısı aşağıdaki gibidir:

ülke AVG(maaş)
Fransa 3700.0000
Türkiye 2600.0000
USA 3500.0000

 

Şimdi de yaş ortalaması 30’un üzerinde olan ülkelerin maaş ortalamalarını getiren sorguyu yazmaya çalışalım. Burada 30 yaş üstü koşulu çalışanlar için değil ülkeler için (yani gruplar) geçerli. O halde yine yukarıdaki sorgularda olduğu gibi ülkelere göre gruplama yapacağız ama bu sefer koşulu gruplar için yazacağız.

 SELECT ülke, AVG(maaş) FROM `kisiler` GROUP BY ülke HAVING AVG(yas) > 30

Sorgunun çıktısı aşağıdaki gibi olacaktır:

ülke AVG(maaş)
Fransa 3700.0000
USA 3500.0000

Sorgunun döndürdüğü sonuç kümesine bakarak iki ülkenin (Türkiye ve Almanya) yaş ortalamalarının 30’dan küçük olduğunu söyleyebiliriz.

Şimdi de çalışan sayısı 1’den fazla olan şehirleri ve çalışan sayılarını getiren sorguyu yazalım.

 SELECT şehir, COUNT(*) FROM `kisiler` GROUP BY şehir HAVING COUNT(*) > 1

Sorgunun çıktısı aşağıdaki gibi olacaktır.

şehir COUNT(*)
Adana 2
Ankara 2
New York 2

 

Şimdi yazacağımız sorgunun açıklaması şöyle: Maaş ortalaması 3000’den fazla olan ülkelerdeki erkek çalışanların maaş ortalaması. Burada gruplamanın ülkelere göre yapılacağı ve yalnızca erkek çalışanların hesaba katılacağı açık.

 SELECT ülke, AVG(maaş) FROM `kisiler` WHERE Cinsiyet=1 GROUP BY ülke HAVING AVG(maaş) > 3000

Sorgunun çıktısı aşağıdaki gibidir. Bu sorguda WHERE ve HAVING ifadeleri birlikte kullandığımızdan farklarını rahatça görebiliyoruz.

ülke AVG(maaş)
Almanya 4000.0000
Fransa 3700.0000
USA 3500.0000

Yukarıdaki sorguyu biraz değiştirelim: Erkek çalışanların sayısı 1’den fazla olan ülkelerin maaş ortalamasını getiren sorgu:

 SELECT ülke, AVG(maaş) FROM `kisiler` WHERE Cinsiyet=1 GROUP BY ülke HAVING COUNT(*) > 1

Sorgunun çıktısı aşağıdaki gibi olacaktır:

ülke AVG(maaş)
Türkiye 2000.0000

Sorguları ve “ne yaptıklarını” dikkatle incelerseniz konuyu daha iyi anlayacaksınız. Bitirmeden önce WHERE ifadesinin her zaman GROUP BY ifadesinden önce geldiğini HAVING’in ise her zaman sonra geldiğini hatırlatalım.

Benim tavsiyem sorguları makalenin başındaki kisiler tablosunu kullanarak zihninizden çalıştırmanız. Sorguların sonuç sonuç kümelerini (çıktılarını) yazmaya çalışın ve buradakilerle karşılaştırın. Bu şekilde sorguların çalışma mantığını daha iyi anlar ve benzer sorguları daha rahat yazmaya başlarsınız.

Herkese kolay gelsin.

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInPrint this pageEmail this to someone

23 Yorum

  1. Having de ikinci bir argüman tanımlanabiliyormu ?
    having sum(net) > 300 ve sum(brut) > 0 den büyük gibi ?

  2. Pardon and ifadesi işe yarıyormuş 😀

  3. SELECT ülke, AVG(maaş) FROM `kisiler` WHERE Cinsiyet=1 GROUP BY ülke HAVING COUNT(*) > 1

    sorguda where cinsiyet=’erkek yada kadin’ olmasi gerekmiyor mu

    sorgularin hepsi degistirilmeli

  4. sorguda cinsiyet=’erkek yada kadın ‘ olmasi gerekmiyormu demişsiniz . Arkadaşımız burada veritabanı şişmesin diye cinsiyet tablosunun ayrı tutulmuş olduğunu düşünmüş(yani sürekli erkek ve kadın yazmasın die ). Tabiki Şehir ve Ülke tablolarıda ayrı tabloda tutulması gerekir ama burda ders niyetinde anlattığından o kadar ilişkiyi kurmamış sanırım.cinsiyet sorgusu kafanızı karıştırmasın kolay gelsin .

  5. Hocam öncelikle emeğine sağlık güzel makele olmuş..

    Ancak

    SELECT ülke, AVG(maaş) FROM `kisiler` WHERE Cinsiyet=1 GROUP BY ülke HAVING AVG(maaş) > 3000

    sorgusunun sonuc olarak ” Erkek çalışanların maaş ortalaması 3000′den fazla olan ülkelerin maaş ortalaması ” nı getireceğini söylemişsin

    aslında bu sorgu bize

    ” Erkek çalışanların maaş ortalaması 3000′den fazla olan ülkelerin erkek çalışanlarının maaş ortalaması ” nı vermez mi ??

    Sonuc ta where Cinsiyet=1 diyerek biz tablomuzdan cinsiyeti Kadin olanlari cikarmis olmuyor muyuz ??

    • admin

      19 Mart 2012 at 23:52

      Sanırım haklısınız ama emin olmak için sorguyu yazıp çalıştırmak lazım. Şu anda veritabanını baştan oluşturup sorgu yazmaya vaktim yok. Siz benzer bir örnek bulabilirseniz buraya ekleriz.

  6. hocam çok iyi bilgi vermissiniz. :)

  7. SQL sorguları ancak bu kadar sade ve güzel anlatılabilir teşekkürler hrzafer:)

  8. Ellerinize sağlık. Ben SQL ve C# eğitimine yeni başladım ve bu tip örnekler, bu tip yazılar benim için çok eğitici oluyor. Emeği geçen herkese teşekkürler tekrar. Çalışmalarınızın devamını dilerim…

  9. Sorgularımda hiç having kullanmamıştım. Sayenizde bunca yıl sonra öğrendim. Elinize sağlık. Gerçekten çok güzel anlatmışsınız. Teşekkürler.

  10. Murat’a katılıyorum.Bu arada gerçekten mükemmel anlatmışsınız.Having her zaman group by dan sonra ve where ise önce geldiğini vurgulamanızda yeni başlayan kişiler için önemli bir vurgu olduğunu belirtip ve zaman harcamanıza teşekkür ediyorum.Murat’ın yorumunu daha sonra inceleyeceğim demişsiniz, evet sanırım orada cümle olarak mantık havası olmuş.SELECT ülke, AVG(maaş) FROM `kisiler` WHERE Cinsiyet=1 GROUP BY ülke HAVING AVG(maaş)> 3000; // Maaş ortalaması’nın 3000′den fazla olan ülkelerdeki erkek çalışanlarının maaş ortalamasını gösteren bir sorgu diyebilirim. İyi çalışmalar herkese!

    • admin

      26 Kasım 2013 at 08:36

      Sorgunun açıklamasını “Maaş ortalaması 3000′den fazla olan ülkelerdeki erkek çalışanların maaş ortalaması” olarak düzelttim. Önceki versiyonda anlatım bozukluğundan kaynaklanan bir hata vardı. Uyarınız sana Murat’a teşekkürler.

  11. Çok teşekkür ederim. Çok acil bir anda yardıma koştu bu sayfa.:)

  12. kafam çok karıştı :S

  13. Peki, Yaş Ortalaması 30 ‘un Üzerinde veya Erkek Olan Kayıtları Nasıl Listeleriz ?
    SELECT ülke, AVG(maaş) FROM `kisiler` GROUP BY ülke HAVING AVG(maaş) > 3000 OR Cinsiyet=1 -> Gibi Ama Bu Sorguyu Çalıştıramadım, Nasıl Bi Düzenleme Yapmam Gerekiyor.

    • “Yaş ortalaması 30’un üzerinde olan ülkeler” ile “erkek olan kişiler” aynı türden, kıyaslanabilir şeyler olmadığından sorgu anlamlı değil. “Yaş ortalaması 30’un üzerinde olan veya bütün kişilerin erkek olduğu ülkeler” gibi bir sorgu mümkün ama. SELECT ülke, AVG(maaş) FROM kisiler GROUP BY ülke HAVING AVG(maaş) > 3000 OR HAVING AVG(cinsiyet) = 1

      • Harun Reşit, İki Ayrı Koşul Var Burada Tabiyki Aynı Türden Olmayacak. Hem Cinsiyetin Nasıl Ortalamasını Alabiliyorsun Bir de İkinci Kez Nasıl HAVING Kullanabiliyosun

    • Ahmet Bey, aslında doğru yazmışsınız fakat parantezleri unuttuğunuz için sorgunuz çalışmıyor. Harun Reşit Bey biraz ezbere cevap veren birisi anladığım kadarıyla, bu yüzden buraya soru sormak pek de mantıklı değil. İngilizceniz orta seviyede veya daha yüksekse, stackoverflow.com gibi bu iş için muhteşem bir kaynak olan siteleri tercih edin derim. İyi günler.

      SELECT ülke, AVG(maaş) AS maaş FROM kisiler GROUP BY ülke HAVING (AVG(maaş) > 3000 OR Cinsiyet=1)

      • Merhaba,

        Parantezler sorguyu çalışır hale getirir ama dönen sonucun anlamlı olacağını sanmıyorum. Sorguları çalıştırmadan kesin bir yorum yapamayacağım. Zira SQL derslerini yazalı uzun zaman oldu ve dersleri hazırlarken kullandığım veritabanı ortamı artık yok. Bu nedenle evet sorguları çalıştırıp denemeden (yani biraz ezberden cevap veriyorum). Maalesef uzun zamandır da siteye yeni bir şey eklemeye hiç vaktim olmuyor. Katkılarınız için teşekkürler.

  14. garib bir kul

    13 Nisan 2015 at 00:00

    Allah razi olsun. Cok faydali oldu gercekten.

  15. Öncelikle, hocamızın bu makale dizisindeki güzel anlatımlarını beğendiğimi belirteyim. Allah razı olsun hocam, güzel bir çalışma olmuş.

    (Yıllar sonraki bir yorum olacak ama…)
    Murat beyle aynı fikirdeyim.

    Birinci olarak;
    1- “Erkek çalışanlarının maas ortalaması 3000 den fazla olan ülkelerin maas ortalamaları” sorulsaydı;
    (“Çalısanları erkek olan ve maas ortalaması 3000 den fazla olan ülkeler” şeklinde de sorulabilirdi.)

    SELECT ulke,avg(maas) FROM kisiler WHERE cinsiyet=1 GROUP BY ulke HAVING AVG(maas)>3000;

    sorgusu doğru olacaktı.

    Ama bize sorulan;
    2- “Maaş ortalaması 3000’den fazla olan ülkelerdeki erkek çalışanların maaş ortalaması” dır.
    Bu durumda doğru sorgu şu şekilde gerçekleştirilebilir. (FROM ifadesinde select kullanımı yaptım. Başka türlü de yapılabilir belki.)

    SELECT k.ulke,avg(maas) FROM KISILER k,(SELECT ulke,avg(maas) FROM kisiler GROUP BY ulke HAVING AVG(maas)>3000) adlandır WHERE adlandır.ulke=k.ulke AND cinsiyet=1 GROUP BY k.ulke;

  16. ellerinize sağlık

  17. En iyi anlatım şeklini siz yapıyorsunuz , devamını bekliyorum

Bir Cevap Yazın

E-posta adresiniz yayınlanmayacak

*

© 2016 Harun Reşit Zafer

Temayı tasarlayanAnders NorenYukarı ↑