Sayfalar

17 Ocak 2013 Perşembe

HR Şeması İle Uygulamalı SQL(Alt Sorgular)

Merhaba Arkadaşlar,

SQL çalışmalarımız tüm hızıyla sürüyor :) Yazılar biraz uzun oluyor ama bunun sebebi uygulamalı olarak deyimleri incelememiz. Eğer siz de bu deyimleri uygulayarak yapıyorsanız sonuçlarınızı karşılaştırabilmeniz adına sorguların çıktılarını da veriyorum.

Şimdi bugün de alt sorguları işleyeceğiz. Hemen kısaca giriş yapalım. Diyelim ki yöneticiniz sizden X kişisinin çalıştığı ülkede çalışan kişilerin maaşlarını görüntüleyen bir rapor istedi. Bu durumda tek bir sorgu ile işin içinden çıkmanız gerçekten zor. İç içe iki sorgu ile çalışmak durumundasınız. Bu gibi durumlarda sorgular hiyerarşik olarak dizilmelidir. Yani içteki sorgudan dönen sonucu dıştaki sorgu işleyerek asıl amaca dair çıktıyı size vermelidir. Mesela verdiğimiz örnekte içteki sorgu X kişisinin çalıştığı ülkeyi çekmelidir. Ana sorgu ise bu şehirde çalışan kişilerin maaşlarını görüntüler.

Alt sorguların amacını açıkladıktan sonra konuya başlayabiliriz.

Alt Sorgu ve Özellikleri
Alt sorguların söz dizimi genelde şu biçimdedir:
SELECT liste
FROM tabloismi
WHERE karsilastirmaoperatoru
    (SELECT liste
     FROM tabloismi);

Bu tip sorgularda öncelikle içteki alt sorgu çalışır. Buradan dönen sonuçlar ana sorgu icra edilir. Yazım tarzına bakılırsa parantez () kullanılarak alt sorgu yazılmalıdır. Ayrıca ana sorgudan ayrıldığını belirtmek ve okunabilirliği artırmak amacıyla alt sorguyu sağdan girintili olacak biçimde vermeniz sorgunuzun görselliğini artıracaktır. Bunun aksini yapsanız da sorgunuz sorunsuz çalışır. Hemen verdiğimiz soruyu sorgulayalım. Sıkı durun sorgu biraz uzun olacak. JOIN bilginizi kullanırsanız anlamakta zorlanmazsınız:

SELECT first_name as isim, salary, c.country_name
FROM employees e JOIN departments d
ON e.department_ıd = d.department_ıd
JOIN locations l
ON d.locatıon_ıd = l.location_id
JOIN countries c
ON l.country_id = c.country_id
WHERE c.country_name =
    (SELECT c.country_name
    FROM employees e JOIN departments d
    ON e.department_ıd = d.department_ıd
    JOIN locations l
    ON d.locatıon_ıd = l.location_id
    JOIN countries c
    ON l.country_id = c.country_id
    WHERE e.fırst_name  = 'Donald');
ISIM                 SALARY            COUNTRY_NAME            
-------------------- ----------------- ------------------------
Alexander            9000              United States of America                 
Bruce                6000              United States of America                 
David                4800              United States of America
...
68 rows selected

Kısaca açıklayalım: Alt sorgu bize 'Donald' isimli şahsın görevli olduğu ülkenin ismini döndürmektedir. Tek bir ülke ismi döner: United States of America. Dolayısıyla tekli karşılaştırma operatörlerini kullanmamız gerekir. Buradaki en ÖNEMLİ nokta burasıdır. Geri kalan bilgiler daha önceki SQL bilgileriniz ile alakalıdır. "Donald isimli kişinin çalıştığı ülke" sorgusundan sadece bir ülke ismi döner. Yani tek durumda normal eşitsizlik ifadelerini kullanmamız gerekir. Bunları hatırlarsak : =, >, <, >=, <=, <> şeklindeydi. Peki alt sorgudan birden çok sonuç dönmesi gerekiyorsa ne tür karşılaştırma operatörleri işimizi görür? Örneğin sorgudaki ismi 'John' ile değiştirirseniz hata mesajı ile karşılaşırsınız: 
Error report:
SQL Error: ORA-01427: tek satırlık alt sorgu birden fazla satır döndürüyor
Yani tek satır operatörü olan = yetersiz kalıyor! = operatörünü IN ile değiştirirseniz sorununuz çözülecektir. Bu kez 103 tane sorgu sonucu gelir ki United Kingdom da sonuçlarınıza eklenmiştir. IN operatörünü hatırlıyor olmalısınız. Tek bir ifadeyi yani ana sorgudaki WHERE şartındaki country_name'i alt sorgudan dönen iki adet ülke ismiyle karşılaştırır. İkisinden biri ile eşleşiyorsa sorgu sonucunda yerini alacaktır.

Bu karmaşık örnekten sonra aklınıza yatması için bir de JOIN'siz basit bir örnek yapalım: Donald isimli kişinin maaşından daha az maaş alan çalışanların maaşlarını listeleyelim:

SELECT last_name, salary
FROM   employees
WHERE  salary <
               (SELECT salary
                FROM   employees
                WHERE  first_name = 'Donald');
LAST_NAME                 SALARY                 
------------------------- ---------------------- 
Colmenares                2500                   
Landry                    2400                   
Markle                    2200  
...
11 rows selected

Burada da küçüktür < operatörünün kullanımını görmüş oldunuz. 

Şimdi öğrendiklerimizi toparlayalım.

Alt Sorgu Tipleri:
Döndürdükleri sonuç sayılarına göre ikiye ayrılırlar:
  • Tek sonuç döndüren alt sorgular: 'Donald' isimli şahsın ülkesinde çalışan kişilerin maaşlarını çektiğimiz sorguda alt sorgudan tek sonuç dönmüştü. Bu gibi alt sorgudan tek sonucun döndüğü sorgulardır. Tekli karşılaştırma operatörleri ile kullanılırlar.Yani; eşittir (=), büyüktür (>), küçüktür (<), büyük eşittir (>=), küçük eşittir (<=), eşit değildir (<>) seçenekleri ile kullanım mümkündür.

    Bu bilgilerin yanı sıra şu da önemlidir: Bir sorguda birden fazla alt sorgu kullanılabilir. Örneğin çalıştığı şehir 'Donald' ile aynı olan ve 'Susan' ile aynı maaşı alan çalışan kimse var mıymış bir bakalım:
    SELECT e.first_name, l.city, salary
    FROM   employees e JOIN departments d
    ON e.department_ıd = d.department_ıd
    JOIN locations l
    ON l.location_id = d.locatıon_ıd
    WHERE  l.city =  
                    (SELECT city
                     FROM   employees e JOIN departments d
                     ON e.department_ıd = d.department_ıd
                     JOIN locations l
                     ON l.location_id = d.locatıon_ıd
                     WHERE  first_name = 'Donald')
    AND    e.salary =
                    (SELECT salary
                     FROM   employees
                     WHERE  first_name = 'Susan');
    FIRST_NAME           CITY                           SALARY                
    -------------------- ------------------------------ ---------
    Shanta               South San Francisco            6500                   

    1 rows selected

    Azıcık zor gibi görünüyor ama hiç de öyle değil :) Eğer yapmakta güçlük çekiyorsanız alt sorguları ayrı bir kenarda tasarlayın. Daha sonra bu sorguları ana sorgunuz ile birleştirin.
  • Çok sonuç döndüren alt sorgular: Ana sorguya bir satırdan daha fazla sonuç gönderir. Çok satırlı operatörlerle birlikte kullanılmalıdır! Bu operatörlerden IN operatörünü öğrenmiştik. Şimdi diğer ikisini öğrenelim:
    • ANY: Bir değeri alt sorgudan dönen bir dizi sonuçla karşılaştırır. Hiçbir satır dönmezse FALSE değeri döndürür. =ANY, != ANY, > ANY, < ANY, <= ANY ve >= ANY ile kullanılır. Örneğin bir değer alt sorgudan dönen herhangi bir değere eşit mi sorusunu =ANY ile araştırırız. Eğer eşit olan bir değer yoksa FALSE değerini görürsünüz.
    • ALL: Bir değeri alt sorgudan dönen bir dizi sonuçla karşılaştırır. Hiçbir satır dönmezse TRUE değeri döndürür. Yine ANY ile aynı operatörlerle kullanılır.
Diğer Notlar:
  • Alt sorgularda grup fonksiyonlarını kullanabilirsiniz. Örneğin IT_PROG job_id'sine sahip olan çalışanların en yüksek maaş alanından daha yüksek maaş alan çalışanları görelim:
    SELECT last_name, job_id, salary
    FROM   employees
    WHERE  salary >
                    (SELECT MAX(salary)
                     FROM   employees
                     WHERE job_id = 'IT_PROG');
    LAST_NAME                 JOB_ID     SALARY                
    ------------------------- ---------- ----------------------
    Hartstein                 MK_MAN     13000                
    Baer                      PR_REP     10000    
    ...
    23 rows selected
  • Ana sorguda GROUP BY ve HAVING ifadelerini kullandığınızda HAVING kısmında alt sorgu kullanmanız sıkıntı oluşturmaz. Ancak alt sorguda GROUP BY ifadesini kullanıyorsanız ana sorguda kesinlikle tekli karşılaştırma operatörlerini kullanamazsınız. Aşağıdaki sorgu hata verecektir:
    SELECT first_name, last_name
    FROM   employees
    WHERE  salary =
                    (SELECT   MIN(salary)
                     FROM     employees
                     GROUP BY department_id);
    Error report:
    SQL Error: ORA-01427: tek satırlık alt sorgu birden fazla satır döndürüyor
  • İç sorgudan herhangi bir sonuç alınamazsa yada NULL ifadesi geri dönerse; o zaman ana sorgu da herhangi bir sonuç döndürmez.

job_id'si 'ST_CLERK' olmayıp, job_id'si 'ST_MAN' olan çalışanlardan daha çok maaş alan çalışanların bilgilerini görüntüleyelim:

SELECT employee_id, first_name, job_id, salary
FROM   employees
WHERE  salary > ANY
                    (SELECT salary
                     FROM   employees
                     WHERE  job_id = 'ST_MAN')
AND    job_id <> 'ST_CLERK';
EMPLOYEE_ID            FIRST_NAME           JOB_ID     SALARY   
---------------------- -------------------- ---------- ----------
100                    Steven               AD_PRES    24000    
101                    Neena                AD_VP      17000    
102                    Lex                  AD_VP      17000 
...
57 rows selected

Aynı sorguyu ALL operatörü ile kullanıp sonuçları yorumlayalım:

SELECT employee_id, first_name, job_id, salary
FROM   employees
WHERE  salary > ALL
                    (SELECT salary
                     FROM   employees
                     WHERE  job_id = 'ST_MAN')
AND    job_id <> 'ST_CLERK';
EMPLOYEE_ID            FIRST_NAME           JOB_ID     SALARY                 
---------------------- -------------------- ---------- ---------------------- 
206                    William              AC_ACCOUNT 8300                   
177                    Jack                 SA_REP     8400 
...
37 rows selected

Bu da demek oluyor ki job_id'si 'ST_CLERK' olmayıp, job_id'si 'ST_MAN' olan çalışanlarının aldığı en yüksek maaştan daha çok maaş alan çalışanların bilgilerini görmek istiyoruz... Zaten ALL ifadesi için şu formülü aklınızda tutun:
  • > ALL : En büyükten daha büyük
  • < ALL : En küçükten daha küçük
  • > ANY: En büyükten daha küçük
  • < ANY: En küçükten daha büyük
  • = ANY: IN ile aynı 
Bu konuyu da burada noktalayabiliriz. Kolay gelsin!


Hiç yorum yok:

Yorum Gönder