Sayfalar

18 Ocak 2013 Cuma

HR Şeması İle Uygulamalı SQL(Küme Operatörleri)

Merhaba arkadaşlar!

Aslında SQL'in zorlu kısımlarını bitirdik sayılır. JOIN, alt sorgular en karmaşık gelebilecek konulardı. Geriye bazı küme operatörleri, DDL, DML ve diğer şema nesneleri ile ilgili işlemler kaldı. Tabi eğer PL/SQL'den bahsediyorsak daha çok konu var demektir. Ama biz burada SQL'i temel alıyoruz.

Bugün küme operatörlerini inceleyeceğiz. Neden küme operatörü diyorum? Çünkü ilkokuldan tanıdığımız küme mantığını tablolar arasında uygulayan basit bir işlemdir. Gerçekte ise "set operatörleri" olarak geçiyor. Burada üç adet operatör tanıyacağız:

  • UNION/UNION ALL: Birleşim işlemi
  • INTERSECT: Kesişim işlemi
  • MINUS: Fark işlemi
Şunu da unutmamak gerekir ki sorgunun çalışması için SELECT ile çektiğiniz ifadelerin sayıları uyuşmalıdır. Yine iki sorgudaki aynı listeye ait veri tipleri eşleşmelidir. Bu iki duruma dikkat ettikten sonra bu operatörlerle çalışmak hiç de zor değildir. Aslında çok fazla da işiniz düşmeyecek bu operatörlere.

Bu operatörlerle çalışırken sanki DISTINCT ifadesini kullanıyormuşsunuz gibi birden fazla aynı olan sonuçlar elimine edilir ve karşınıza tek bir sonuç olarak çıkarılır. Bu UNION ALL operatörü için geçerli değildir.Ve yine UNION ALL dışındaki diğer operatörlerle çalışırken sorgunuzun sonucu artan sıralama ile getirilir. Eğer sıralama ile oynamak isterseniz sorgunun en sonuna ORDER BY ekleyebilirsiniz. Bu ORDER BY ifadesi bir kerelik kullanım içindir ve ilk SELECT sorgusuna ait sonuçları düzenler.

Şimdi tek tek bu operatörleri uygulayarak tanıyalım:

1.) UNION/UNION ALL Operatörü
Bu işlem farklı iki sorgudan dönen sonuçları toplayarak yani birleşimini alarak karşınıza getirir. UNION operatöründe çift sonuçlar düzeltilirken, UNION ALL operatöründe aynen getirilirler. Şimdi yukarıda dediğimiz şartlara dikkat ederek yani SELECT listesindeki sütunların birbirleriyle uyumunu sağlayarak bir sorgu oluşturalım.

SELECT employee_id, job_id
FROM   employees
UNION
SELECT employee_id, job_id
FROM   job_history;
EMPLOYEE_ID            JOB_ID     
---------------------- ---------- 
100                    AD_PRES    
101                    AC_ACCOUNT 
101                    AC_MGR   
...
115 rows selected

Bu sorgu bize örnek teşkil etmek için ideal. Çünkü her iki tabloda da ortak sütun isimleri mevcut. Yani hem veri tipleri uyuşuyor hem de sütunlar. Sonuçlar employee_id sütununa göre sıralı gelmiştir. Hatta job_id sütunu da mümkün olduğunca sıralı olarak gelmiştir. Yani ORDER BY employee_id, job_id gibi bir düzenleme olmuştur. 

Yukarıdaki sorgunun ne anlam ifade ettiğini açıklayalım. Sorguda amaçlanan çalışanların şimdiki ve önceki işlerine dair job_id'leri görüntülemekti. Yani eğer bir çalışan hiç iş değiştirmemişse sonuç tablosunda bir satır işgal edecektir. 100 nolu çalışanın yaptığı gibi.. Ancak birden fazla iş değiştiren çalışanlar ise sonuç tablosunda birleşim operatörünün yapısı gereği bu sayı kadar görüntülenecektir. 115 - 107 = 8 çalışanın iş değiştirdiğini buradan anlayabiliyoruz.

Aynı sorguyu UNION ALL ile deneyelim. Bakalım her iki tabloda tekrar eden kaç kayıt söz konusu. Bu kez ORDER BY ifadesini de kullanacağız çünkü kullanmazsak UNION ALL'da sonuçların sırasız geleceğini biliyor olmalıyız.

SELECT employee_id, job_id
FROM   employees
UNION ALL
SELECT employee_id, job_id
FROM   job_history
ORDER BY employee_ıd;
EMPLOYEE_ID            JOB_ID     
---------------------- ---------- 
...
176                    SA_REP     
176                    SA_MAN    
176                    SA_REP
...
200                    AD_ASST    
200                    AD_ASST    
200                    AC_ACCOUNT ...

117 rows selected

Sonuçlardan herşey görülüyor. 117 - 155 = 2 tekrar içermesi gerek. Bu tekrarları da 176 ve 200 id'li çalışanlarda görebiliyoruz.Anlıyoruz ki bu iki çalışan daha önceden çalışmış olduğu işlerden birinde çalışıyor.

Gelin bu tekrar eden satırları farklı bir yöntemle bulalım:

2.) INTERSECT Operatörü
Dediğimiz gibi her iki veya daha fazla sorgudan dönen ortak sonuçları sonuç tablosunda gösterir. Yani kesişim işlemini icra eder. Şimdi iş değiştirip aynı işine tekrar dönen kişileri yukarıda UNION ALL ile el ile tespit etmiştik. Şimdi bunları INTERSECT ile tespit edelim.

SELECT employee_id, job_id
FROM   employees
INTERSECT
SELECT employee_id, job_id
FROM   job_history;
EMPLOYEE_ID            JOB_ID     
---------------------- ---------- 
176                    SA_REP     
200                    AD_ASST    

2 rows selected


Bu iki kişi işlerini belki de birden çok kez değiştirdiler. Ancak burada şunu anlıyoruz. Şu an çalıştıkları iş ile geçmişte çalıştıkları iş aynı olan bu iki çalışan mevcut. Diğer tüm çalışanlar şimdiki işlerini geçmişte daha önce hiç yapmamışlar. 

Şunu belirtelim: employees tablosunda çalışanlara ait güncel iş bilgileri tutuluyor. job_id de ise çalışanların geçmişteki iş bilgileri saklanıyor. Yani çalışan iş değiştirdiği anda bu tabloya eski işi kaydediliyor ve yeni tablo güncelleniyor. Sorguları bu bilgiler ışığında inceleyiniz.

3.) MINUS Operatörü
Bu operatör ile iki sorgu arasında farklı olan satırları keşfetmek istediğinizde çalışırsınız. Yani kümelerdeki fark işleminin bir sonucudur. Mesela şunu merak ediyor olabiliriz: Acaba kaç tane çalışan; işe girdiğinden bu güne kadar hiç işini değiştirmemiştir? Hemen bakalım:

SELECT employee_id
FROM   employees
MINUS
SELECT employee_id
FROM   job_history;
EMPLOYEE_ID            
---------------------- 
100                    
103                    
104 
...
100 rows selected

Demek ki 100 tane çalışan iş tarihinde sadece bir işte çalışmıştır. 

Konuyla ilgili dikkat çeken bir nokta daha kaldı. Diyelim ki SELECT sorgularındaki tablo sütunları ne yaptıysak eşleşemedi. Yani bir şekilde bir sorgunun çalışması gerekiyor ancak sütun değerlerini tutturamıyoruz. Bunu düzenlemenin bir yolu var. Eşleşemeyen satırlar için kendiniz bir değer verirseniz sonuçları okumanız mümkün olur. Bu değer bazen 0, bazen NULL olarak seçilir. Aşağıdaki basit örneklerle konuyu anlamaya çalışalım:

Normalde olması gereken sorgu tipi şu şekildedir:

SELECT A, B
UNION|UNION ALL|INTERSECT|MINUS
SELECT A, B

Ancak olmadığını düşünürsek şu kullanımlarla işi çözebiliriz:

SELECT A, B, 0
UNION|UNION ALL|INTERSECT|MINUS
SELECT A, B, C

Üstteki kullanımda ikinci sorgudaki C sütunu ile uyuşan bir sütun birinci sorguda bulunmadığı için bu değerler yerine 0 yazılacaktır. Şu kullanım da uygundur:

SELECT TO_CHAR(Null), B, C
UNION|UNION ALL|INTERSECT|MINUS
SELECT A, B, TO_CHAR(Null)

Uyuşan sütunlar sadece 1 tanedir ve bu da B sütunudur. 1. sorgudaki C ile 2. sorguda buna karşılık gelen bir sütun yoktur. Aynı şekilde 2. sorgudaki A ile 1. sorguda buna karşılık gelen bir sütun adı yoktur. Karşılık bulunamayan bu değerler NULL ile temsil edilir. Burada diğer dönüşüm fonksiyonlarını kullanmanız da gerekebilir. Biz tüm sütunların veri tiplerinin CHAR olduğunu varsayarak bu örneği verdik. Örneğin C sütunu sayısal olsaydı TO_NUMBER dönüşüm fonksiyonu işimizi görecekti.

Bununla ilgili bir kaç kullanım örneği inceleyelim:

SELECT location_id, department_name "Bölüm",TO_CHAR(NULL) "Şehir"  
FROM departments
UNION
SELECT location_id, TO_CHAR(NULL) "Bölüm", state_province
FROM locations;
LOCATION_ID            Bölüm                          Şehir 
---------------------- ------------------------------ -----------
1000                                                          
1100                                                          
1200                                                  Tokyo Prefecture 
...
50 rows selected

Görüldüğü gibi eşleşmenin olmadığı satırlar NULL olarak geri dönmüştür. Burada da her ne kadar anlamsız olsa da konuyu öğrenmemize yardımcı olabilecek bir diğer sorgu görülüyor. Sayısal bir sütunu eşleştirmek için 0, karakter veri tipindeki bir sütunu eşleştirmek için de TO_CHAR(Null) kullanılıyor:

SELECT employee_id, TO_CHAR(Null), commıssıon_pct
FROM   employees
UNION
SELECT employee_id, job_id,0
FROM   job_history;
EMPLOYEE_ID            TO_CHAR(NULL) COMMISSION_PCT         
---------------------- ------------- ---------------------- 
100                                                         
101                    AC_ACCOUNT    0                      
101                    AC_MGR        0  
...
117 rows selected


Commission_Pct sütununda 0 olmayan yani NULL olan sütunlar gerçekte de NULL olduğu için sonuçta bu şekilde görülmüştür.

Konu burada sona erdi. Hafif ve anlaşılması kolay bir konu. Bu örnekleri anlayıp uyguladıktan sonra anlamamanız için bir neden yok. Kolay gelsin!

Hiç yorum yok:

Yorum Gönder