3.5. Tablolar Arası Katılım
Buraya kadar, yaptığımız sorgulamalarda her seferinde sadece bir tabloya erişildi. Oysa sorgulamalar aynı andan birden çok tabloya erişebildiği gibi, aynı tabloya birden fazla kez erişerek satırlara daha çeşitli yaptırımlar uygulayabilir. Aynı anda birden fazla satır ya da birden fazla tabloya erişen sorgulara katılımlı sorgu denir. Sözgelimi (daha önce oluşturduğumuz tablolardaki) tüm illerin hava durumlarını ve konumlarını aynı anda listelemek istiyoruz. Bunun için hava_durumu
tablosundaki tüm il
sütunları ile iller
tablosundaki tüm ad
sütunlarını karşılaştırıp, aynı olan satır çiftlerini seçmek gerekir.
Bilginize
Bu sadece kavramsal bir modeldir. Katılımlı sorgular, aslında, her olası satır çiftini karşılaştırmaktan biraz daha verimli bir anlamda uygulanır ama bu işlemi kullanıcı görmez.
Yukarıda bahsedilen işlemi şu sorgu ile elde edebiliriz:
SELECT * FROM hava_durumu JOIN iller ON il = ad;
Sonuç:
il | asg_sck | azm_sck | yağış | tarih | ad | konum ---------------+---------+---------+-------+------------+---------------+----------- San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53) San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53) (2 satır)
Çıktıda dikkat edilmesi gereken iki nokta bulunmakta:
-
Haywrad şehri için hiçbir çıktı alınmadı dikkat edildiyse. Bunun nedeni ise
iller
tablosunda Hayward adlı bir il olmaması ve dolayısıylaJOIN
bu şehri eledi. İleride bunun nasıl düzeltilebileceği üzerinde durulacak. -
Bir diğer dikkat çeken nokta ise, illerin adını yazan iki tane sütun olması. Bunun sebebi
hava_durumu
veiller
tablosunun birleştirilmesidir. Pratikte bu istenmeyen bir sonuçtur. Böyle bir durumda buna neden olan*
ifadesi yerine açıkça listelenmesini istediğimiz sütunları yazarak bu işi halledebiliriz:SELECT il, asg_sck, azm_sck, yağış, tarih, konum FROM hava_durumu JOIN iller ON il = ad;
Tablolardaki tüm sütun isimleri farklı olduğundan çözümleyici hangi ismin hangi tabloya ait olduğunu bulur. Ama bunu daha da açıkça belirtmek isimler aynı olduğunda dahi sorun çıkmasını önler ve tavsiye edilen de budur:
SELECT hava_durumu.il, hava_durumu.asg_sck, hava_durumu.azm_sck, hava_durumu.yağış, hava_durumu.tarih, iller.konum FROM hava_durumu JOIN iller ON hava_durumu.il = iller.ad;
Birleştirme sorgusundaki tüm sütun adlarını nitelemek yaygın olarak iyi bir uygulama olarak kabul edilir, böylece daha sonra tablolardan birine yinelenen sütun adlarından biri eklenirse sorgu başarısız olmaz.
Şimdiye kadar gördüğümüz katılım sorguları ayrıca şu şekilde de yazılabilir:
SELECT * FROM hava_durumu, iller WHERE il = ad;
Bu sözdizimi, SQL-92'de tanıtılan JOIN
/ON
sözdizimine dayanır. Tablolar basitçe FROM
deyiminde listelenir ve karşılaştırma ifadesi WHERE
deyimine eklenir. Bu eski örtük sözdiziminden ve daha yeni açık JOIN
/ON
sözdiziminden elde edilen sonuçlar aynıdır. Ancak sorgunun okuyucusu için, açık sözdizimi anlamını anlamayı kolaylaştırır: Daha önce koşul, diğer koşullarla birlikte WHERE
deyimine karıştırılmışken, birleştirme koşulu kendi anahtar sözcüğüyle tanıtılır.
Şimdi Hayward kayıtlarına nasıl kavuşacağımızı işleyeceğiz. İstediğimiz şey hava_durumu
tablosu üzerinde tarama yapıp, iller
tablosunda bunlarla eşleşen satırları bulmak. Eğer iller
tablosunda herhangi bir eşleşme bulamazsak, o sütun iller
tablosu alanında boş gözükecek. Bu tür sorgulama işlemleri haricen katılım (outer join) olarak bilinir. (Şimdiye kadar gördüğümüz katılım sorgularında ise hep dahilen katılım (inner join) kullanmıştık.) Komut şöyle görünür:
SELECT * FROM hava_durumu LEFT OUTER JOIN iller ON hava_durumu.il = iller.ad;
Sonuç:
il | asg_sck | azm_sck | yağış | tarih | ad | konum ---------------+---------+---------+-------+------------+---------------+----------- San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53) San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53) Hayward | 37 | 54 | | 1994-11-29 | | (3 satır)
Bu sorguya sola haricen katılımlı (left outer join) sorgu denir. Böyle adlandırılmasının sebebi soldaki tablonun tüm satırları en az bir kere listelenirken, sağda yer alan tablonun sadece soldaki tablonun satırlarıyla eşleşen satırlarının listelenmesidir. Bir sol-tablo satırı çıktılanırken sağ-tabloda bu satırla eşleşen bir satır yoksa, sağ-tablonun sütunları boş kalır.
- Alıştırma:
-
Ayrıca, sağa haricen katılımlı (right outer join) ve iki yönlü haricen katılımlı (full outer join) sorgu türleri de var. Bunların ne yaptığını da siz bulmayı deneyin.
Ayrıca, bir tabloyu kendine katılımlı olarak da sorgulayabiliriz ve buna kendine katılımlı sorgu denir. Bir örnek olarak, diğer hava durumu kayıtlarının sıcaklık aralığı içinde kalan hava durumu kayıtlarını bulmak isteyelim. Yani, her hava_durumu
satırının asg_sck
ve azm_sck
sütununu diğer hava_durumu
satırlarının asg_sck
ve azm_sck
sütunu ile karşılaştıracağız. Bunu şu sorgu ile yapabiliriz:
SELECT w1.il, w1.asg_sck AS low, w1.azm_sck AS high, w2.il, w2.asg_sck AS düşük, w2.azm_sck AS yüksek FROM hava_durumu w1 JOIN hava_durumu w2 ON w1.asg_sck < w2.asg_sck AND w1.azm_sck > w2.azm_sck;
Sonuç:
il | low | high | il | düşük | yüksek ---------------+-----+------+---------------+-------+-------- San Francisco | 43 | 57 | San Francisco | 46 | 50 Hayward | 37 | 54 | San Francisco | 46 | 50 (2 satır)
Burada katılımın sol ve sağ taraflarını ayırabilmek için hava_durumu
tablosunu W1
ve W2
olarak yeniden isimlendirdik. Ayrıca, bu çeşit isimlendirmeleri aynı şeyleri uzun uzadıya yazmaktan kaçınmak için diğer sorgularda da kullanabilirsiniz. Örnek:
SELECT * FROM hava_durumu w JOIN iller c ON w.il = c.name;
Bu tarz kısaltmalarla sıkça karşılaşacaksınız.