Ders 06 / 18
Yerleşik İşlevler
Satır başına çalışan dizgi, sayı ve tarih işlevleri; karakter ile bayt uzunluğu ayrımı, tam sayı bölmesi ve tarih işlevlerinin standarda en uzak alan olması.
İçindekiler
Önceki ders boş değeri dönüştüren üç yapıyı kullandı: COALESCE, NULLIF ve CASE.
Üçü de tek bir satırın değerlerini alıp tek bir değer üreten skaler işlevlerdir
(scalar function) — sonuç kümesinin satır sayısını değiştirmezler, yalnız sütun değerlerini
dönüştürürler.
Bu ders aynı ailenin geri kalanını kurar: metin, sayı ve tarih üzerinde çalışan yerleşik işlevler. Ailenin öğretici tarafı yalnız ne yaptıkları değil, adlandırmalarının ne kadar değişken olduğudur. Yerleşik işlevler, standart SQL ile motor lehçesinin en görünür biçimde ayrıldığı alandır.
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
Uzunluk: Karakter mi, Bayt mı
Metnin uzunluğunu veren işlev, ölçtüğü şey konusunda net olmalıdır. Bilgisayarlar Nasıl Çalışır kursunda kurulan ayrım burada doğrudan görünür: bir karakter birden çok bayt kaplayabilir.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT LENGTH('Körlük') AS karakter, LENGTH(CAST('Körlük' AS BLOB)) AS bayt; SQL
karakter bayt -------- ---- 6 8
Altı karakterlik sözcük sekiz bayt tutuyor: ö ve ü harflerinin her biri iki bayt.
Uzunluk işlevinin karakter mi bayt mı saydığı motora göre değişir; bazı motorlarda ayrı
adlarla iki işlev bulunur, bazılarında tipin metin mi ikili veri mi olduğuna bakılır.
Alan sınırı denetiminde bu ayrım doğrudan hataya dönüşür — karakterle ölçüp baytla saklayan
bir denetim, Türkçe metinde beklenenden erken taşar.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik, LENGTH(baslik) AS uzunluk FROM kitap ORDER BY uzunluk DESC, baslik; SQL
baslik uzunluk ----------------- ------- Tehlikeli Oyunlar 17 Tutunamayanlar 14 Anayurt Oteli 13 Kum Kitabı 10 Sessiz Ev 9 Körlük 6 Yaban 5
Kesme, Arama, Değiştirme
Metnin bir parçasını almak için parça alma işlevi kullanılır. Standart yazım ile yaygın yazım burada ayrılır.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT SUBSTRING('2024-01-09' FROM 1 FOR 4) AS yil; SQL
Parse error near line 3: near "FROM": syntax error
SELECT SUBSTRING('2024-01-09' FROM 1 FOR 4) AS yil;
error here ---^
Standarttaki SUBSTRING(… FROM … FOR …) yazımı bu motorda tanınmıyor. Motorun kabul
ettiği yazım, argümanları virgülle ayıran biçimdir.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT ad, SUBSTR(kayit_tarihi,1,4) AS kayit_yili FROM uye ORDER BY uye_id; SQL
ad kayit_yili ------ ---------- Ayşe 2023 Mehmet 2023 Zeynep 2024 Emre 2024 Selin 2024 Burak 2025
Bir alt dizginin konumunu bulan işlevin adı da motora göre değişir. Standarttaki
POSITION(… IN …) yazımı yerine bu motorda ayrı adlı bir işlev bulunuyor.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT eposta, INSTR(eposta,'@') AS konum FROM uye WHERE eposta IS NOT NULL ORDER BY uye_id; SQL
eposta konum ----------------- ----- [email protected] 5 [email protected] 7 [email protected] 5 [email protected] 6
Konum 1‘den başlıyor. SQL’de dizgi konumları bir tabanlıdır; Programlama Temelleri
kursundaki sıfır tabanlı dizin alışkanlığı burada geçerli değildir ve bir kaydırma hatasının
sık kaynağıdır.
Değiştirme ve kırpma işlevleri daha az değişkendir.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik, REPLACE(baslik,'Kitabı','Kitap') AS degistirilmis FROM kitap WHERE baslik LIKE '%Kitab%'; SELECT '[' || TRIM(' Körlük ') || ']' AS kirpilmis; SQL
baslik degistirilmis ---------- ------------- Kum Kitabı Kum Kitap kirpilmis --------- [Körlük]
Kırpma işlevi öntanımlı olarak iki uçtaki boşlukları alır; hangi karakterlerin kırpılacağını belirten ve yalnız bir uçtan kırpan biçimleri de vardır.
Sayı İşlevleri ve Bölme
Sayısal işlevlerin çoğu tek biçimlidir, ama bölme davranışı ayrık durur.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT ABS(-7) AS mutlak, ROUND(2.555, 2) AS yuvarlak, 17 % 5 AS kalan, 17 / 5 AS bolum, 17.0 / 5 AS ondalik; SQL
mutlak yuvarlak kalan bolum ondalik ------ -------- ----- ----- ------- 7 2.56 2 3 3.4
17 / 5 işlemi 3 verdi, 17.0 / 5 işlemi 3.4. Bölmenin tam sayı mı ondalık mı
olduğunu belirleyen şey, işlenenlerin tipidir. Bu davranış motora göre değişir: bazı
motorlar iki tam sayının bölümünü de ondalık üretir. Taşınabilir yazım, bölmeden önce en az
bir işleneni ondalık tipe çevirmektir.
Kalan işleci de iki yazımla bulunabilir ve yazımlar aynı tipi üretmeyebilir.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT 17 % 5 AS islecle, MOD(17,5) AS islevle; SQL
islecle islevle ------- ------- 2 2.0
Aynı sayı, biri tam sayı diğeri ondalık olarak döndü. Sonuç bir karşılaştırmaya ya da gruplamaya girecekse bu fark önemlidir.
Yuvarlamada da dikkat edilecek bir nokta var: ondalık sayılar ikilik gösterimde tam karşılanamaz — Bilgisayarlar Nasıl Çalışır kursundaki kayan noktalı sayı dersinin sonucu burada da geçerlidir. Parasal hesaplarda yuvarlama işlevine değil, ondalık tipe güvenilir.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik, basim_yili, basim_yili % 10 AS son_hane FROM kitap WHERE basim_yili IS NOT NULL ORDER BY kitap_id; SQL
baslik basim_yili son_hane ----------------- ---------- -------- Körlük 1995 5 Tutunamayanlar 1972 2 Kum Kitabı 1975 5 Yaban 1932 2 Sessiz Ev 1983 3 Tehlikeli Oyunlar 1973 3
Tarih İşlevleri
Tarih, standardın en zayıf uygulandığı alandır. Standartta tarihten parça çıkarmak için bir yükleme benzeri yazım, tarihe süre eklemek için ise bir aralık tipi tanımlıdır. İkisi de her motorda bulunmaz.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT EXTRACT(YEAR FROM alis_tarihi) AS yil FROM odunc; SQL
Parse error near line 3: near "FROM": syntax error
SELECT EXTRACT(YEAR FROM alis_tarihi) AS yil FROM odunc;
^--- error here
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT alis_tarihi + INTERVAL '14' DAY AS son_gun FROM odunc; SQL
Parse error near line 3: near "DAY": syntax error
SELECT alis_tarihi + INTERVAL '14' DAY AS son_gun FROM odunc;
error here ---^
İki standart yazım da bu motorda çalışmadı. Motorun sunduğu karşılıklar başka adlar taşıyor.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT odunc_id, alis_tarihi, strftime('%Y', alis_tarihi) AS yil, date(alis_tarihi,'+14 days') AS son_gun FROM odunc WHERE odunc_id <= 4 ORDER BY odunc_id; SQL
odunc_id alis_tarihi yil son_gun -------- ----------- ---- ---------- 1 2025-01-10 2025 2025-01-24 2 2025-02-02 2025 2025-02-16 3 2025-02-11 2025 2025-02-25 4 2025-03-01 2025 2025-03-15
İki tarih arasındaki farkı gün cinsinden almak da motora özgü bir yazım gerektirir.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT odunc_id, alis_tarihi, iade_tarihi, CAST(julianday(iade_tarihi) - julianday(alis_tarihi) AS INTEGER) AS gun FROM odunc WHERE iade_tarihi IS NOT NULL AND odunc_id <= 5 ORDER BY odunc_id; SQL
odunc_id alis_tarihi iade_tarihi gun -------- ----------- ----------- --- 1 2025-01-10 2025-01-24 14 2 2025-02-02 2025-02-20 18 4 2025-03-01 2025-03-15 14 5 2025-03-18 2025-04-02 15
Üçüncü ödünç kaydı listede yok: iade tarihi boş olduğu için fark hesaplanamaz ve koşul onu eledi. Boş değer kuralı burada da işliyor.
Tarih işlevlerinin motora bağlılığı pratik bir sonuç doğurur: tarih hesabı sorgunun içine gömüldüğünde sorgu taşınamaz hale gelir. Taşınabilirlik gerekiyorsa tarih aritmetiği ya uygulama katmanına alınır ya da motora özgü kısmı tek bir yerde toplanır. Ayrıca tarih sütununun saat dilimi taşıyıp taşımadığı da motora ve tipe göre değişir; saat dilimsiz bir sütunda yapılan gün hesabı, saat dilimi sınırında bir gün kayabilir.
Özet
- Skaler işlevler satır başına çalışır ve sonuç kümesinin satır sayısını değiştirmez.
- Uzunluk işlevinin karakter mi bayt mı saydığı motora bağlıdır; ASCII dışı metinde ikisi ayrışır.
- Dizgi konumları bir tabanlıdır; parça alma ve konum bulma işlevlerinin standart yazımı her motorda bulunmaz.
- Bölmenin tam sayı mı ondalık mı olacağını işlenenlerin tipi belirler ve bu davranış motora göre değişir.
- Tarih işlevleri standarttan en çok ayrılan alandır; parça çıkarma ve süre ekleme yazımları motordan motora değişir.
- Tarih hesabında boş değer kuralı sürer: bir ucu boş olan fark hesaplanamaz.
Sonraki Adım
Buraya kadar bütün sorgular tek bir tablodan okudu. Oysa normalleştirilmiş bir şemada anlamlı sorular tek tabloya sığmaz: “hangi üye hangi kitabı ödünç aldı” sorusunun yanıtı üç tabloya dağılmıştır, çünkü ödünç tablosunda yalnız kimlikler var. Sonraki konu tabloları birleştiren yan tümceyi kurar ve ilk dersi eşleşen satırların kesişimini — iç birleştirmeyi — ele alır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.