Ders 03 / 18
Koşullar
Karşılaştırma işleçleri, mantıksal bağlaçların önceliği, aralık ve liste denetimleri, örüntü eşleme ile kaçış karakteri ve büyük/küçük harf davranışının motora bağlı olması.
İçindekiler
Önceki ders sonuç kümesinin sütunlarını belirledi: hangi sütunlar, hangi adlarla, hangi
ifadelerle. Satırlar konusunda tek bir araç kullanıldı — tek bir eşitlik koşulu. Bir
sorgunun döndürdüğü satır sayısını belirleyen asıl yan tümce ise WHERE.
WHERE yan tümcesi, FROM yan tümcesinin ürettiği her satır için bir mantıksal ifade
değerlendirir ve yalnızca doğru sonuç veren satırları geçirir. Bu ders o ifadenin
yazılabileceği bütün biçimleri kurar: karşılaştırma, bağlaç, aralık, liste ve metin
örüntüsü.
Aşağıdaki blok şemayı ve örnek veriyi kurar; dersin bütün sorguları bu blokta oluşturulan
kutuphane.db dosyası üzerinde çalışır.
rm -f kutuphane.db sqlite3 kutuphane.db <<'SQL' CREATE TABLE sube (sube_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, sehir TEXT NOT NULL); CREATE TABLE kitap (kitap_id INTEGER PRIMARY KEY, baslik TEXT NOT NULL, yazar TEXT NOT NULL, basim_yili INTEGER, sube_id INTEGER REFERENCES sube(sube_id)); CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL, eposta TEXT, kayit_tarihi TEXT NOT NULL); CREATE TABLE odunc (odunc_id INTEGER PRIMARY KEY, kitap_id INTEGER NOT NULL REFERENCES kitap(kitap_id), uye_id INTEGER NOT NULL REFERENCES uye(uye_id), alis_tarihi TEXT NOT NULL, iade_tarihi TEXT); INSERT INTO sube VALUES (1,'Merkez','Ankara'),(2,'Bahçelievler','Ankara'), (3,'Kadıköy','İstanbul'),(4,'Konak','İzmir'); INSERT INTO kitap VALUES (1,'Körlük','José Saramago',1995,1),(2,'Tutunamayanlar','Oğuz Atay',1972,1), (3,'Kum Kitabı','Jorge Luis Borges',1975,2),(4,'Yaban','Yakup Kadri',1932,2), (5,'Sessiz Ev','Orhan Pamuk',1983,3),(6,'Anayurt Oteli','Yusuf Atılgan',NULL,3), (7,'Tehlikeli Oyunlar','Oğuz Atay',1973,NULL); INSERT INTO uye VALUES (1,'Ayşe','Demir','[email protected]','2023-02-14'), (2,'Mehmet','Kaya','[email protected]','2023-05-30'),(3,'Zeynep','Arslan',NULL,'2024-01-09'), (4,'Emre','Yıldız','[email protected]','2024-03-22'),(5,'Selin','Aydın',NULL,'2024-11-05'), (6,'Burak','Şahin','[email protected]','2025-01-18'); INSERT INTO odunc VALUES (1,1,1,'2025-01-10','2025-01-24'),(2,2,1,'2025-02-02','2025-02-20'), (3,1,2,'2025-02-11',NULL),(4,3,3,'2025-03-01','2025-03-15'),(5,4,3,'2025-03-18','2025-04-02'), (6,1,4,'2025-04-05','2025-04-19'),(7,5,4,'2025-04-21',NULL),(8,2,5,'2025-05-02','2025-05-30'), (9,7,1,'2025-05-14','2025-05-28'),(10,3,5,'2025-06-03',NULL),(11,6,2,'2025-06-11','2025-06-25'), (12,4,4,'2025-06-20','2025-07-04'); SQL
Karşılaştırma İşleçleri
Altı karşılaştırma işleci vardır: =, <>, <, >, <=, >=. Eşitsizlik işlecinin
standart yazımı <> biçimindedir; çoğu motor != yazımını da kabul eder, ancak taşınabilir
olan <> yazımıdır.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik, basim_yili FROM kitap WHERE basim_yili > 1975; SQL
baslik basim_yili --------- ---------- Körlük 1995 Sessiz Ev 1983
Yedi kitaptan ikisi döndü. Geri kalan beş kitabın dördü koşulu sağlamıyor; beşincisinin
— Anayurt Oteli — basım yılı bilinmiyor. Bilinmeyen bir değerin 1975’ten büyük olup
olmadığı da bilinmez, dolayısıyla satır geçmez. Boş değerin koşullardaki davranışı beşinci
dersin konusu; şimdilik akılda tutulacak kural şudur: boş değer içeren bir karşılaştırma
ne doğru ne yanlıştır, ve WHERE yalnız doğruyu geçirir.
Metin karşılaştırması da aynı işleçlerle yapılır.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik, yazar FROM kitap WHERE yazar <> 'Oğuz Atay'; SQL
baslik yazar ------------- ----------------- Körlük José Saramago Kum Kitabı Jorge Luis Borges Yaban Yakup Kadri Sessiz Ev Orhan Pamuk Anayurt Oteli Yusuf Atılgan
Metin karşılaştırmasında iki dizenin eşit sayılıp sayılmayacağını harmanlama
(collation) belirler. Harmanlama, karakter sırasını ve büyük/küçük harf ile aksan
duyarlılığını tanımlar; öntanımlı harmanlama motora göre değişir. Aynı sorgu bir
motorda 'oğuz atay' değerini eşit sayabilir, diğerinde saymayabilir.
Mantıksal Bağlaçlar ve Öncelik
Koşullar AND, OR ve NOT ile birleştirilir. Üçünün önceliği farklıdır: NOT en
yüksek, sonra AND, en düşük OR. Bu, Programlama Temelleri kursundaki işleç önceliği
kuralının aynısıdır ve aynı hataya yol açar.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik, yazar, basim_yili FROM kitap WHERE yazar = 'Oğuz Atay' OR yazar = 'Orhan Pamuk' AND basim_yili > 1980; SQL
baslik yazar basim_yili ----------------- ----------- ---------- Tutunamayanlar Oğuz Atay 1972 Sessiz Ev Orhan Pamuk 1983 Tehlikeli Oyunlar Oğuz Atay 1973
Sonuçta 1980 öncesi iki kitap var. Niyet “bu iki yazardan birinin 1980 sonrası kitapları”
olsaydı sonuç yanlış olurdu. AND daha yüksek öncelikli olduğu için koşul, “yazar Oğuz
Atay ya da (yazar Orhan Pamuk ve yıl 1980’den büyük)” biçiminde ayrıştırıldı.
Ayraç niyeti düzeltir.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik, yazar, basim_yili FROM kitap WHERE (yazar = 'Oğuz Atay' OR yazar = 'Orhan Pamuk') AND basim_yili > 1980; SQL
baslik yazar basim_yili --------- ----------- ---------- Sessiz Ev Orhan Pamuk 1983
Kural: AND ile OR aynı koşulda geçtiğinde ayraç yazılır. Öncelik kuralına güvenmek
doğru sonuç verse bile, sorguyu okuyanın niyeti çıkarmasını zorlaştırır.
Aralık ve Liste
İki karşılaştırmayla yazılan aralık koşulunun kısa bir yazımı vardır.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik, basim_yili FROM kitap WHERE basim_yili >= 1970 AND basim_yili <= 1980; SQL
baslik basim_yili ----------------- ---------- Tutunamayanlar 1972 Kum Kitabı 1975 Tehlikeli Oyunlar 1973
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik, basim_yili FROM kitap WHERE basim_yili BETWEEN 1970 AND 1980; SQL
baslik basim_yili ----------------- ---------- Tutunamayanlar 1972 Kum Kitabı 1975 Tehlikeli Oyunlar 1973
İki sorgu aynı satırları döndürüyor. BETWEEN her iki uca da dahildir; 1970 ve
1980 değerleri aralığın içindedir. Bu nokta sık atlanır ve özellikle tarihlerde hataya
yol açar: bir ayın tamamını BETWEEN ile seçmek isterken ayın son gününü kapsayan sınırın
gün mü yoksa gün ile saat mi olduğu karışır. Zaman bileşeni taşıyan sütunlarda alt sınırı
dahil, üst sınırı hariç yazan biçim (>= ve <) daha güvenlidir.
Sonlu bir değer kümesi için IN yazılır.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik, yazar FROM kitap WHERE yazar IN ('Oğuz Atay','Orhan Pamuk'); SQL
baslik yazar ----------------- ----------- Tutunamayanlar Oğuz Atay Sessiz Ev Orhan Pamuk Tehlikeli Oyunlar Oğuz Atay
IN, OR ile bağlanmış eşitliklerin kısaltmasıdır. Uzun listelerde okunabilirliği
artırır ve motora tek bir küme denetimi olarak planlanabilecek bir yapı sunar. Değillemesi
NOT IN biçiminde yazılır ve listede boş değer bulunduğunda beklenmedik davranır; bu tuzak
beşinci derste ölçülecek.
Değillemenin Sınırı
NOT bir koşulu tersine çevirir, ama “tersi” sözcüğü boş değer varken yanıltıcıdır.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik, sube_id FROM kitap WHERE sube_id = 1; SELECT baslik, sube_id FROM kitap WHERE NOT (sube_id = 1); SQL
baslik sube_id -------------- ------- Körlük 1 Tutunamayanlar 1 baslik sube_id ------------- ------- Kum Kitabı 2 Yaban 2 Sessiz Ev 3 Anayurt Oteli 3
İlk sorgu iki satır, ikincisi dört satır döndürdü. Toplam altı; oysa tabloda yedi kitap
var. Kayıp satır Tehlikeli Oyunlar: şube kimliği boş olduğu için ne birinci koşulu ne de
değillemesini sağlıyor. Bir koşul ile değillemesinin birlikte tablonun tamamını vermesi,
yalnızca ilgili sütunda boş değer yoksa geçerlidir.
Örüntü Eşleme
Metin içinde arama LIKE işleciyle yapılır. İki joker karakter vardır: % sıfır ya da
daha çok karakteri, _ tam olarak bir karakteri karşılar.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik FROM kitap WHERE baslik LIKE '_um%'; SQL
baslik ---------- Kum Kitabı
Örüntü, “herhangi bir karakter, ardından um, ardından herhangi bir şey” diyor ve yalnız
bir başlığa uyuyor.
Asıl soru şudur: LIKE büyük/küçük harfe duyarlı mıdır? Yanıt motora göre değişir ve
aynı motor içinde bile karakterin ASCII olup olmamasına göre değişebilir.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik FROM kitap WHERE baslik LIKE 'k%'; SQL
baslik ---------- Körlük Kum Kitabı
Küçük harfli k ile yazılan örüntü, büyük K ile başlayan iki başlığı yakaladı: bu
motorda ASCII harfler için LIKE harf duyarsızdır. Aynı motor ASCII dışı harflerde ise
duyarlıdır.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik FROM kitap WHERE baslik LIKE '%ö%'; SELECT baslik FROM kitap WHERE baslik LIKE '%Ö%'; SQL
baslik ------ Körlük
İkinci sorgu hiç satır döndürmedi. Körlük başlığında ö var, ama Ö ile yazılan örüntü
eşleşmedi — harf katlaması yalnız ASCII aralığında uygulandı. Türkçe metinlerde bu, sessiz
sonuç kaybının doğrudan kaynağıdır.
Duyarlılığı sorgunun kendisiyle sabitlemek de tam çözüm değildir, çünkü harf dönüştürme işlevleri de aynı sınıra takılabilir.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT UPPER('Körlük') AS buyuk, LOWER('KÖRLÜK') AS kucuk; SQL
buyuk kucuk ------ ------ KöRLüK kÖrlÜk
Dönüştürme ASCII harfleri değiştirdi, ö ve Ö olduğu gibi kaldı. Doğru çözüm, sorguyu
yamamak değil, sütuna harf ve aksan duyarsız bir harmanlama tanımlamak ya da motorun
Unicode desteğini etkinleştirmektir; ikisi de motora göre değişir.
Örüntünün kendisinde % ya da _ karakteri aranıyorsa kaçış karakteri bildirilir.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT 'Indirim %20' AS metin, 'Indirim %20' LIKE '%!%%' ESCAPE '!' AS kacisli, 'Indirim %20' LIKE '%%%' AS kacissiz UNION ALL SELECT 'Indirim 20', 'Indirim 20' LIKE '%!%%' ESCAPE '!', 'Indirim 20' LIKE '%%%'; SQL
metin kacisli kacissiz ----------- ------- -------- Indirim %20 1 1 Indirim 20 0 1
ESCAPE '!' bildirimi, !% yazımını “gerçek yüzde işareti” olarak okutur. Kaçışsız
örüntü ise her iki metne de uyuyor, çünkü %%% yazımı “herhangi bir şey” demektir. Ölçüt
sütunundaki 1 ve 0 değerleri mantıksal doğru ve yanlışın gösterimidir; boole değerinin
nasıl yazıldığı da motora göre değişir.
Özet
WHEREyalnızca doğru sonuç veren satırları geçirir; ne doğru ne yanlış olan satır elenir.NOTen yüksek,ANDorta,ORen düşük önceliklidir; ikisi bir arada geçtiğinde ayraç yazılır.BETWEENher iki uca dahildir; zaman bileşeni olan sütunlarda alt sınır dahil, üst sınır hariç yazım daha güvenlidir.IN,ORile bağlanmış eşitliklerin kısaltmasıdır.- Bir koşul ile değillemesi tablonun tamamını yalnızca ilgili sütunda boş değer yoksa verir.
LIKEişlecinde%ve_joker karakterlerdir,ESCAPEbunları gerçek karakter yapar; harf duyarlılığı motora ve karakterin ASCII olup olmamasına göre değişir.
Sonraki Adım
Buraya kadar hangi satırların döneceği belirlendi, ama hangi sırayla döneceği hiç belirlenmedi. Çıktılardaki sıra motorun okuma biçiminden geliyor ve garanti değil. Sonraki ders sonuç kümesini sıralayan yan tümceyi, çok anahtarlı sıralamayı, boş değerlerin sıralamadaki yerini ve sonucu ilk N satırla sınırlamanın standart ile yaygın yazımları arasındaki farkı ele alır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.