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.
21 Haziran 2011 at 05:44
Having de ikinci bir argüman tanımlanabiliyormu ?
having sum(net) > 300 ve sum(brut) > 0 den büyük gibi ?
21 Haziran 2011 at 05:50
Pardon and ifadesi işe yarıyormuş 😀
28 Haziran 2011 at 08:46
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
24 Temmuz 2011 at 13:24
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 .
18 Mart 2012 at 10:07
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 ??
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.
27 Kasım 2020 at 05:41
Selamlae Murat bey, çok önemli bir detaydan bahsetmişsiniz. Having’de cinsiyet koşulu olamdığı için hocanın dediği doğru. Sizin dediğiniz şekilde olması için kod
SELECT ülke, AVG(maaş) FROM `kisiler` WHERE Cinsiyet=1 GROUP BY ülke HAVING AVG(maaş) > 3000 and Cinsiyet =1
Şeklinde olmalı
13 Haziran 2012 at 18:10
hocam çok iyi bilgi vermissiniz. 🙂
24 Aralık 2012 at 10:01
SQL sorguları ancak bu kadar sade ve güzel anlatılabilir teşekkürler hrzafer:)
18 Haziran 2013 at 09:16
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…
10 Ekim 2013 at 01:31
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.
26 Kasım 2013 at 07:34
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!
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.
05 Aralık 2013 at 07:58
Çok teşekkür ederim. Çok acil bir anda yardıma koştu bu sayfa.:)
23 Aralık 2013 at 11:42
kafam çok karıştı :S
05 Ağustos 2014 at 07:51
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.
06 Ağustos 2014 at 00:38
“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
06 Ağustos 2014 at 06:09
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
25 Haziran 2015 at 07:16
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)
26 Haziran 2015 at 13:56
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.
28 Ağustos 2021 at 08:35
galiba sorunuzun cevabı bu şekilde olacak
select * from kisiler where(ulke in (select ulke from kisiler group by ulke having avg(yas)>30) or cinsiyet=1)
28 Ağustos 2021 at 08:51
kusura bakmayın soruyu cevaplamam 7 yıl sürdü (soruyu cevaplamak için üniversite eğitimi almam gerekti)
öncelikle yaş ortalaması 30’dan fazla olanlar veya cinsiyeti erkek olanları istemişsiniz galiba sorunuzun cevabı bu:
select * from kisiler where(ulke in (select ulke from kisiler group by ulke having avg(yas)>30) or cinsiyet=1);
NOT: Bu arada Harun Reşat beyin cinsiyetlerin ortalamasını alma fikri çok hoşuma gitti, gruplandırılmış verileri cinsiyetlerine göre ayırmam gerekirse kesinlikle kullanacağım.
Herkese iyi günler, iyi çalışmalar dilerim.
13 Nisan 2015 at 00:00
Allah razi olsun. Cok faydali oldu gercekten.
21 Nisan 2015 at 17:21
Ö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;
13 Mayıs 2015 at 13:34
ellerinize sağlık
30 Eylül 2015 at 07:54
En iyi anlatım şeklini siz yapıyorsunuz , devamını bekliyorum
27 Haziran 2019 at 14:19
harika anlatım tesekkurler
11 Aralık 2019 at 02:47
Merhabalar,
Şimdi ilk örnekte 12 satır var oradaki 12 maaşın en düşük ortalamasının %25’ini nasıl hesaplatırız yada böyle bir şey mümkün mü?
09 Ocak 2020 at 02:31
Teşekkürler.