Select İfadesi ve Sorgular

Bir önceki yazımızda SQL konusuna girmiş ve SQL konusunda ön bilgileri vermiştik. Şimdi o yazımızda bahsettiğimiz Select ifadesini biraz daha açmamız gerekiyor. Select’in kullanım detayları hakkında ayrıntılı bilgileri, daha gelişmiş select sorgularına inceleyerek, SQL’e olan hakimiyetimizi güçlendirebiliriz.

Veritabanı Kavramı yazımızda veritabanının ne olduğunu, SQL Nedir? yazımızda da veritabanımızda nasıl sorgular yazabileceğimizi incelemiştik. SQL’le ilgili yazımızda “SQL’in öğrenmesi kolay bir dil” olduğunu da söylemiştik. Evet SQL öğrenmesi kolaydır. Ama uzmanlaşması zordur. Biraz bu anlamıyla briç ve satranca benzer. Briç, spor kabul edilen bir kağıt oyunudur. Satranç da bir taş oyunu. Bu oyunların ikisini de bir günde öğrenebilirsiniz. Ama bir günlük bir oyuncu olarak çıkıp iyi bir briç masasına oturamazsınız mesela. Bilmeniz, uzman olduğunuz anlamına gelmiyor. SQL de bunlara benzer. Dil olarak kolay olmasına rağmen; kombinasyonları, kompleks yapıları çözmesi tecrübe gerektirir. Bunun için SQL konusunda ne kadar uzmanlaşırsanız, o kadar “aranan” bir uzman haline gelirsiniz.

SQL konusunda uzmanlaşırken, en önemli konumuz SELECT ifadeleri olacak tabi ki. Çünkü bir önceki yazımızda SELECT’ten ve WHERE’den bahsetmiştik. Ancak SELECT, arkasına alabildiği ifadeler ile çok yetenekli bir komut haline gelebilir. Bu yüzden bir çok ek ifade hakkında bilgi sahibi olunması gerekir.

 

ORDER BY

Select sorgularını sıralı hale getirmek için kullanılır.

Yukarıdaki sorguda select ifadesinin arkasına order by ifadesi ekleyerek listemizi sıralı hale getirdik. Order by’ın arkasına eklediğimiz alan adları hangi alana göre sıralama yaptığımızı belirtiyor. Yukarıdaki sorguda order by OgrenciAdi ekleyerek, listemizi OgrenciAdi’na göre alfabetik sıralamış olduk.

İfadenin sonuna bir sıralama tipi eklemezsek otomatik olarak sıralama asc ifadesi eklemiş gibi çalışır. Yani küçükten büyüğe (ascending) sıralı olarak listemiz gelir. desc ise tam tersi (küçükten büyüğe) bir sıralama yapmamızı sağlar.

Şimdi varyasyonları anlayabilmek için şöyle bir sıralama yapalım. Öğrencilerimizi doğum yıllarına (günlerine göre değil) sıralayalım. Doğum yılları aynı olan öğrencileri de kendi arasında numarasına göre ters sıralayalım. Ama bu sıralamaları sadece isminde ‘a’ harfi bulunan öğrenciler için yapalım:

Şimdi sorgumuzu dikkatle inceleyelim.

select * from Ogrenciler: Ogrenciler tablosundaki kayıtları bütün alanlarıyla (*) gelecek şekilde listeliyoruz.

where OgrenciAdi like ‘%a%’ Ogrenciler tablomuzdaki kayıtlardan sadece OgrenciAdi’nda “a” harfi geçen kayıtlar gelecek şekilde listeliyoruz. Yukarıdaki listede gelen Hikmet Şimşek gibi kayıtlar, içinde “a” bulunmadığı için bu listemize giremedi mesela. Görüldüğü gibi hem where’i hem order’ı aynı anda kullanabiliriz. Where ifadeleri Order’dan önce yazılmalıdır.

order by Year(DogumTarihi), OgrenciNo desc: Sıralamamızı önce doğum tarihinin yılına göre yaptık. ASC veya DSC koymadığımız için doğum yılına göre ascending (küçükten büyüğe) sıralı hale geldi. Bu sıralama sayesinde 1981 doğumlu Ayşe Fatma listemizde otomatikman ilk sıraya yerleşti. Çünkü diğer bütün kayıtlar 1982 doğumluyken, Ayşe Fatma 1981 doğumlu olduğu için, order by’ımızın ilk kriterine göre 1. sırayı garantiledi. Order by ifademizin virgülden sonra ikinci bir kriteri daha bulunuyor. OgrenciNo desc. Bu Year(DogumTarihi) sıralamasından sonra, eğer bu kritere göre “aynı” kayıtlar varsa, kendi aralarında sıralama biçimini ifade ediyor. Yani doğum yılı aynı olan kayıtları OgrenciNo alanına göre sırala dedik. Sonuna desc koyarak OgrenciNo sıralamasının ters olmasını istedik. Bu sayede 1982 doğumlu öğrenciler, öğrenci numarasına göre ters sıralandı.

Bu kez yukarıdaki sorgumuzda küçük bir değişiklik yapalım. Desc ifadesini OgrenciNo’dan silelim. Yıla göre kullanalım.

Bakın bu kez yıl ters sıralandığı için 1982 doğumlu öğrenciler, 1981 nolu öğrencilerin üstüne çıktı. Daha önce OgrenciNo’yu desc sıralamışken bu kez asc sıraladık. Yani 1982 doğumlu öğrenciler de kendi aralarında numaralarına göre küçükten büyüğe sıralandı. Burada asc kelimesini yazmak zorunda değildik. Eğer order by Year(DogumTarihi) desc, OgrenciNo yazsadık, sıralama yine aynı olacaktı. Çünkü asc veya desc yazmazsak, SQL bunu asc yazılmış kabul eder.

 

GROUP BY 

Sorgularımızı verdiğimiz alanlara göre gruplamımızı sağlar.

Hemen bir önceki örnek üzerinden devam edelim. Yine Ogrenciler tablomuzda, isminde “a” geçen öğrenciler üzerinde listeleme yapıyoruz. Ancak bu kez öğrencileri doğum yıllarına göre grupluyoruz. group by Year(DogumTarihi) ifadesiyle doğum yılları aynı olan öğrencileri grup haline getirdik. Ve sıralamamızı doğum yılına göre ters yaptık. Tablomuzdan da doğum yıllarını ve kayıt sayıları seçtik (select Year(DogumTarihi), count(*)). Burada dikkat edilmesi gereken group by’da yazmadığımız alanları, select veya order bölümlerinde kullanamayız. Yani şu sorgu hata verir:

Çünkü group by’da olmayan bir alanı listelemek istiyorsunuz. Ama kayıtlarınız doğum yıllarına göre gruplandı. Yani listeleyeceğiniz kayıtlar içinde birden fazla OgrenciNo bulunabilir. Aşağıdaki sorguda ise hata almazsınız:

Select’imizde group by ile kullandığımız alanlar dışında sadece SQL Nedir? yazımızda bahsettiğimiz aggregate (kümeleme) fonksiyonları kullanılabilir (count, sum, min, max, avg). Örneğimizde count kullanarak grupladığımız alan sayısını listeliyoruz.

Group by ifadesi Where’den sonra, Order’dan önce kullanılmalıdır. Yani where ifadesi kullanacaksak, where kısmını group by’dan sonra yazamayız. Order kullanacaksak da group by’dan önce yazamayız.

 

HAVING

Grupladığımız alanlar arasından süzme yapabilmemizi sağlar.

Yine yukarıda yazdığımız sorgulardan birini, biraz daha geliştirdik. Yine adında “a” olan öğrencileri doğum yıllarına göre grupladık ve sıraladık (ters). Ama bu kez having ekleyip gruplanmış kayıt sayıları 5’den büyük olanları listeledik. Ve listemize 1 kayıtlı 1981 gelmedi. Sadece 6 kayıtlı 1982 geldi. Having’i where gibi kullanabiliriz. Ama having içinde, OgrenciAdi’ni kullanamayız mesela. Çünkü gruplanmış alanlar arasında OgrenciAdi yok. Having sadece gruplanmış kayıtlar üzerinde çalışır. Yani kayıtları grupladıktan sonra süzmek için having’i kullanırız. Kayıtları henüz gruplamadan süzmek için where kullanırız.

 

JOIN

Join ifadesi, farklı tabloları ilişkiler vasıtasıyla birbirine bağlayıp, birden fazla tablodan sonuçlar üretebilmemizi sağlar.

Örneğin veritabanımızda Sınavlar diye bir tablo var. Ve şuanda içinde 2 adet sınavı, giren öğrencinin numarasını, ders numarasını, sınava giriş tarihi ve öğrencinin sınavdan aldığı puanı barındırıyor.

Evet kayıtlar güzelce girilmiş. Ancak bunu bu şekilde raporlarsak, kullanıcıya çok şey ifade etmeyebilir. Çünkü öğrenci numaralarını, aklında tutmak yerine, öğrenci isimlerini görmek isteyebilir kullanıcılar. E bu veri bizim Ogrenci tablomuzda zaten vardı. İki tarafta da öğrenci numaraları var. Dolayısıyla biz gerçekte sınava giren öğrencinin sadece numarasını değil, isimlerini de biliyoruz. İşte join ifadesi burada devreye giriyor.

Az önceki sorgumuza Join ile bir tablo daha bağlayıverdik. Sinavlar tablosundan yaptığımız select’e, join ile Ogrenciler tablosunu da bağladık. join Ogrenciler on Ogrenciler.OgrenciNo = Sinavlar.OgrenciNo ifadesiyle bu bağlantıyı sağlamış olduk. Fakat bağlarken, anahtar olarak OgrenciNo alanlarını kullandık. Yani Ogrenciler tablosundaki OgrenciNo alanına göre, Sinavlar tablosundan çektiğimiz kayıtlara Ogrenciler tablosundaki ilgili kaydı da eklemiş olduk. Artık çok daha anlamlı bir liste var.

As ifadesi veya Alias kavramı join’leri kullanırken büyük kolaylıklar sağlar. Alias kavramıyla tablolara takma isimler vererek, daha hızlı ve kısa sorgular yazabiliriz. Gelin join’lerimize alias’lar ekleyerek daha güzel bir liste hazırlayalım.

Diyelim okul müdürümüz 27 Ekim 2017 günü Matematik ve Fizik derslerinden sınav yaptı. Sistem Matematik sınavına 1, Fizik sınavına 2 numarasını verdi. Bazı öğrenciler raporlu olduğu için bu sınavlara ertesi gün katıldı. Bu sınavların bütün sonuçlarını öğretmenler sistemimize girdi. Daha sonra da bizden müdür, bu iki sınava giren öğrencileri, giriş tarihlerini ve hangi dersten kaç puan aldıklarını sordu. İşte sistemimizden bu soruya yanıt verebileceğimiz kod:

Gördüğünüz gibi sürekli tablo isimlerini yeniden yazmak yerine, çağırdığım yerlere As ifadesini koyarak her tabloya bir alias (takma isim) atadım. Ve bu daha kısa takma isimleri tablo adlarının yerine kullanmaya başladım.

Görüldüğü gibi select çektiğim Sinavlar tablosunun yanında Ogrenciler ve Dersler tablosuna da join kullanarak bağlantı kurdum. Ogrenciler tablosuna OgrenciNo, Dersler tablosuna DersNo alanıyla eriştim. select O.OgrenciAdi, S.SinavTarihi, D.DersAdi, S.Puan from Sinavlar as S ifadesinde de görebileceğiniz gibi, * deyip bütün alanları listelemek yerine de, sadece ilgili tablodan (alias kullanarak) ihtiyacım olan alanları listeledim. Bu şekilde kullanıcının ihtiyacı olmayan; OgrenciNo, DersNo gibi bilgileri boşu boşuna listelememiş oldum.

Join kapsamlı sorgular yazmak için olmazsa olmazımız. Ve kendi içinde de türlere ayrılıyor. Kısaca bunlara da değinelim:

INNER JOIN: Yukarıda kullandığımız join çeşididir. Başına inner yazmadan join yazarsanız sistem bunu inner join kabul eder. İki tabloda da ilgili kayıtların olması gerekir. Yani yukarıdaki örnekte biri gidip matematik sınav sonuçlarını tablodan silerse, matematik sonuçları listemizde görüntülenmez. Veya matematik dersi Dersler tablosundan silinirse, listemizde öğrencilerin Matematik sınavlarını artık göremeyiz. Inner join’de ilgili kayıtların On ifadesinden sonra kendisini veya alias’ını yazdığımız iki tabloda da bulunması gerekir.

Şimdi Dersler tablosundan Matematik kaydını silelim ve yukarıdaki sorgumuzu tekrar yazalım.

Bakın Sinavlar tablosunda ilgili kayıtlar durmasına rağmen, DersNo = 1 olan kayıt Dersler tablosunda artık bulunmadığı için, Sinavlar tablosundaki sınav sonuçları listelenmedi.

LEFT JOIN: Inner join veya sadece join yazmak yerine left join yazarsak, kaydın on ifadesinden sonra sola yazdığımız tabloda olması yeterlidir. Yani join Dersler as D on S.DersNo = D.DersNo veya inner join Dersler as D on S.DersNo = D.DersNo yazdığımızda DersNo’yu barındıran kaydın hem Dersler hem Sınavlar tablosunda olması gerekiyordu, listelenebilmesi için. Ancak bunlar yerine left join Dersler as D on S.DersNo = D.DersNo yazarsak, kaydın S’de yani Sinavlar’da bulunması listelenmesi için yeterli olacaktır. Hemen uygulayalım:

Bakın Dersler tablosunda, 1 nolu dersin karşılığı olmamasına rağmen, 1 nolu dersin sinavlarından alınan sonuçlar listelendi. Sadece D.DersAdi alanından artık bir sonuç dönemedi ve dersin adını bulamadık.

RIGHT JOIN: Left join’in tam tersi. Bu kez Dersler tablosundaki bütün kayıtlar gelir. Sinav tablosunda karşılığı olsa da, olmasa da.

Görüldüğü gibi Dersler tablosunda, sinav kaydı olmayan dersler de listemize geldi.

FULL JOIN: Her iki tablodaki kayıtlar da, diğer tabloda karşılığı olsa da olmasa da listelenir.

 

UNION

İki farklı select sorgusunu tek bir listede birleştirmemize yarar.

Örneğin bizden lisemizdeki bütün öğrencilerin ve bütün derslerin tek bir listede sorgusu istenirse şunu yazarız:

Görüldüğü gibi Ogrenciler tablosundan OgrenciAdi listesini çektik. Bu listeye ayrıca Dersler tablosundaki DersAdi listesini de ekledik. İki tablodaki kayıtlar tek bir sütunda birleştirildi. Sütun adı olarak da OgrenciAdi’na Madde diye alias atadığımız için sütun adımız da Madde oldu. Çünkü Union’larda sütun adı ilk select’teki ad olarak kabul edilmektedir.

Birden fazla alanı da union tablosunda kullanabiliriz.

UNION ALL: Union’ı tek başına kullandığımızda tamamen aynı kayıtları tekrar listelemez. Yani iki tabloda da aynı No ve Ad olan kayıtlar olsaydı union ile bir kez listelenecekti. Union’ın sonuna all eklediğimizde aynı kayıtlar tekrar tekrar listelenecektir.

 

SQL’de OPERATÖRLER

Sql’deki operatör kullanımı diğer dillere oldukça benzer. Örneklerde de gördüğünüz gibi =, <, >, <=, >= ve <> opeartörlerini SQL’de de sık sık kullanıyoruz. Bunların dışında bahsedilmesi gereken operatörlerden biri de betweendir. Select * from Ogrenciler where OgrenciNo between 1 and 5 sorgusu bize öğrenci numarası 1 ile 5 arasında olan kayıtların listesini verecektir. 1 ve 5 de bu sorguya dahildir. Dolayısıyla bu ifade; Select * from Ogrenciler where OgrenciNo >= 1 and OgrenciNo <= 5 ifadesinin kısaltılmışıdır.

 

MANTIKSAL OPERATÖRLER (AND, OR vs)

Diğer dillerdeki mantıksal operatörler SQL’de de geçerlidir. Where, on, having gibi deyimlerden sonra kullandığımız mantıksal operatörler aracılığıyla şartlarımızı arttırabiliriz.

Bizden Matematik sınavında 5 ve daha fazla not alan öğrencilerin listesinin istendiğini kabul edelim. Dikkat edelim, iki şartımız var. Hem sınav matematik sınavı olacak, hem de 5 ve daha üzeri not alınmış olacak, listeleme için:

where D.DersAdi = ‘Matematik’ and S.Puan >= 5 bölümünde kullandığımız AND koşullarımızın sayısını ikiye çıkardı. Ders tablosundaki DersAdi alanı “Matematik” olacak, aynı zamanda Sinavlar tablosundaki Puan alanı da 5 ve 5’den büyük olacak.

Bir değişik senaryo daha. Okul müdürümüz, 5’den düşük not alan öğrenciler için bir bütünleme sınavı yapmaya karar verdi. Ancak ayın 28’inde yapılan sınavda da yanlış soru olduğunu tespit etti. Dolayısıyla ayın 28’inde sınava giren öğrencilerin de sınavlarını geçersiz sayıp bütünleme sınavına girme hakkı verdi. Ve bize hangi öğrencilerin sınava girmesi gerektiğini sordu. Yani öğrenci sınava 28 Ekim’de girmiş olacak veya herhangi bir tarihte girdiği sınavdan 5’den düşük not alacak. Ona bir liste verelim:

where S.SinavTarihi = ‘2017-10-28’ or S.Puan < 5 ifadesine koyduğumuz or komutu, bize bu listeyi verme imkanı sağladı. Yani and komutunda olduğu gibi iki şartın da gerçekleşmesini beklemedi, kaydı getirmek için şartlardan birinin gerçekleşmesini yeterli kabul etti.

SQL bundan ibaret değil elbette. Ancak veritabanlarını kabul edilebilir bir şekilde kullanmanız için; SQL Nedir? yazımızda anlatılanlarla beraber, bu yazımızı kavramanız yeterli olacaktır. Bu konuları öğrendiğiniz zaman; veritabanlarından kendi basit sorgularınızı yazabilir, istediğiniz şekilde listelemeleri gerçekleştirebilirsiniz.

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir