Ders 15 / 18
Satır Ekleme
INSERT deyiminin sütun listeli ve konumsal biçimleri, tek deyimde çok satır, sorgu sonucunu tabloya yazma, çatışma davranışı ve eklemenin işlem içinde yapılmasının ölçülen etkisi.
İçindekiler
Şema kuruldu ve değiştirilebilir durumda. Sıradaki soru içine veriyi nasıl koyduğumuz.
INSERT deyimi görünüşte kursun en yalın deyimidir — bir tablo adı, bir değer listesi —
ama iki noktada ayrışır: değerlerin sütunlara nasıl bağlandığı ve eklemenin kaç işlem
içinde yapıldığı. İkincisi, aynı veriyi yazan iki betik arasında yüzlerce kat fark
üretebilir.
Tek Satır Eklemek
Deyimin iki yazımı vardır. Sütun listeli yazımda hangi değerin hangi sütuna gittiği deyimde yazılıdır. Konumsal yazımda sütun listesi atlanır ve değerler tablodaki sütun sırasına göre eşlenir.
sqlite3 :memory: <<'SQL' .headers on .mode column CREATE TABLE uye ( uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL, eposta TEXT UNIQUE, kayit_tarihi TEXT NOT NULL, durum TEXT NOT NULL DEFAULT 'etkin' ); INSERT INTO uye (uye_id, ad, soyad, eposta, kayit_tarihi) VALUES (1,'Ayşe','Demir','[email protected]','2023-02-14'); INSERT INTO uye VALUES (2,'Mehmet','Kaya','[email protected]','2023-05-30','askida'); INSERT INTO uye VALUES (3,'Zeynep','Arslan',NULL,'2024-01-09'); SELECT * FROM uye; SQL
Parse error near line 15: table uye has 6 columns but 5 values were supplied uye_id ad soyad eposta kayit_tarihi durum ------ ------ ----- ----------------- ------------ ------ 1 Ayşe Demir [email protected] 2023-02-14 etkin 2 Mehmet Kaya [email protected] 2023-05-30 askida
İlk deyim durum sütununu yazmadı ve varsayılan değeri aldı. İkincisi bütün sütunları
sırayla verdi. Üçüncüsü konumsal yazımı kullandı ama altı sütunluk tabloya beş değer
gönderdi ve reddedildi.
Sütun listesi bu örnekte yalnızca bir yazım tercihi gibi görünür; sürdürülebilirlik
açısından ise ikisi eşit değildir. Bir sütun eklendiğinde ya da sütun sırası
değiştiğinde konumsal yazım ya hata verir ya da — daha kötüsü — tipler uyduğu için
değerleri yanlış sütunlara yazar. Önceki dersteki ALTER TABLE ADD COLUMN deyimi tam da
bunu yapan bir değişikliktir. Sütun listesi yazılırsa şema değişikliği deyimi etkilemez.
Kalıcı kodda ekleme deyimleri sütun listesiyle yazılır; konumsal yazım komut satırında
hızlı denemeler için kalır.
Tek Deyimde Çok Satır
VALUES sözcüğünden sonra virgülle ayrılmış birden çok satır yazılabilir. Motor bunu
tek bir deyim olarak işler.
sqlite3 :memory: <<'SQL' .headers on .mode column CREATE TABLE sube (sube_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, sehir TEXT NOT NULL); INSERT INTO sube (sube_id, ad, sehir) VALUES (1, 'Merkez', 'Ankara'), (2, 'Bahçelievler', 'Ankara'), (3, 'Kadıköy', 'İstanbul'); SELECT count(*) AS eklenen FROM sube; SQL
eklenen ------- 3
Tek deyim olması yalnızca yazımı kısaltmaz, davranışı da belirler: deyim bölünmez. Satırlardan biri bir kısıtı ihlal ederse hiçbiri yazılmaz.
sqlite3 :memory: <<'SQL' .headers on .mode column CREATE TABLE sube (sube_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, sehir TEXT NOT NULL); INSERT INTO sube VALUES (1,'Merkez','Ankara'); INSERT INTO sube (sube_id, ad, sehir) VALUES (3, 'Kadıköy', 'İstanbul'), (1, 'Merkez', 'Ankara'), (4, 'Konak', 'İzmir'); SELECT * FROM sube ORDER BY sube_id; SQL
Runtime error near line 6: UNIQUE constraint failed: sube.sube_id (19) sube_id ad sehir ------- ------ ------ 1 Merkez Ankara
Çakışan satır ikinci sıradaydı; buna rağmen ondan önceki Kadıköy de sonraki Konak da tabloya girmedi. Bir deyimin ya tamamı uygulanır ya da hiçbiri — bu, İlişkisel Kuram kursunda atomiklik olarak adlandırılan özelliğin deyim düzeyindeki görünümüdür.
Sorgu Sonucunu Eklemek
VALUES yerine bir SELECT yazılabilir. Bu biçim, veriyi uygulamaya taşımadan bir
tablodan diğerine aktarır; okuma ve yazma tek deyimde olur.
sqlite3 :memory: <<'SQL' .headers on .mode column CREATE TABLE odunc ( odunc_id INTEGER PRIMARY KEY, kitap_id INTEGER NOT NULL, uye_id INTEGER NOT NULL, alis_tarihi TEXT NOT NULL, iade_tarihi TEXT ); 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'); CREATE TABLE odunc_arsiv ( odunc_id INTEGER PRIMARY KEY, kitap_id INTEGER NOT NULL, uye_id INTEGER NOT NULL, gun_sayisi INTEGER NOT NULL ); INSERT INTO odunc_arsiv (odunc_id, kitap_id, uye_id, gun_sayisi) SELECT odunc_id, kitap_id, uye_id, CAST(julianday(iade_tarihi) - julianday(alis_tarihi) AS INTEGER) FROM odunc WHERE iade_tarihi IS NOT NULL; SELECT changes() AS aktarilan; SELECT * FROM odunc_arsiv; SQL
aktarilan --------- 3 odunc_id kitap_id uye_id gun_sayisi -------- -------- ------ ---------- 1 1 1 14 2 2 1 18 4 3 3 14
SELECT listesindeki ifadeler hedef sütunlarla sırayla eşlenir; adların örtüşmesi
gerekmez, sütun sayısı ve tipleri uymalıdır. Sorgunun WHERE koşulu hangi satırların
aktarılacağını belirler: iade edilmemiş ödünç dışarıda kaldı.
changes() çağrısı son deyimin etkilediği satır sayısını verir. Adı motora göre değişir,
ancak karşılığı her motorda bulunur ve toplu işlemlerde beklenen sayının doğrulanması için
kullanılır. julianday gün farkını hesaplayan bir tarih işlevidir, CAST ise sonucu tam
sayıya çevirir.
Eklenen Satırı Geri Okumak
Birincil anahtarı motor üretiyorsa, eklenen satırın anahtarı ekleme sonrasında bilinmez. Pek çok motor bunun için ekleme deyimine bir çıktı listesi eklemeye izin verir.
sqlite3 :memory: <<'SQL' .headers on .mode column CREATE TABLE uye ( uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL, kayit_tarihi TEXT NOT NULL, durum TEXT NOT NULL DEFAULT 'etkin' ); INSERT INTO uye (ad, soyad, kayit_tarihi) VALUES ('Emre','Yıldız','2024-03-22') RETURNING uye_id, ad, durum; INSERT INTO uye (ad, soyad, kayit_tarihi) VALUES ('Selin','Aydın','2024-11-05') RETURNING uye_id, ad, durum; SQL
uye_id ad durum ------ ---- ----- 1 Emre etkin uye_id ad durum ------ ----- ----- 2 Selin etkin
Anahtar sütunu hiç yazılmadı; motor onu üretti ve varsayılan durumla birlikte deyimin
çıktısında verdi. RETURNING yazımı motora göre değişir: kimi motorlar destekler,
kimileri son üretilen anahtarı veren ayrı bir işlev sunar. Ekleme sonrası anahtara
ihtiyaç duyulduğunda ilk sorulacak soru, kullanılan motorun bunu hangi yolla verdiğidir.
Çatışma Durumunda Ne Olacağı
Var olan bir anahtarla ekleme yapıldığında öntanımlı davranış hatadır. Kimi işlerde istenen ise “varsa güncelle, yoksa ekle” davranışıdır.
sqlite3 :memory: <<'SQL' .headers on .mode column CREATE TABLE sube (sube_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, sehir TEXT NOT NULL); INSERT INTO sube VALUES (1,'Merkez','Ankara'); INSERT INTO sube (sube_id, ad, sehir) VALUES (1, 'Merkez Şube', 'Ankara') ON CONFLICT (sube_id) DO UPDATE SET ad = excluded.ad; INSERT INTO sube (sube_id, ad, sehir) VALUES (1, 'Yok Sayılacak', 'Ankara') ON CONFLICT (sube_id) DO NOTHING; SELECT * FROM sube; SQL
sube_id ad sehir ------- ----------- ------ 1 Merkez Şube Ankara
İlk deyim çatışmayı yakalayıp adı güncelledi, ikincisi çatışmayı sessizce yok saydı.
excluded, eklenmeye çalışılan ama çatışma yüzünden yazılamayan satırı adlandırır.
Bu yazımın adı ve ayrıntısı motora göre değişir; kimi motorlar aynı işi başka bir anahtar sözcükle yapar. Değişmeyen nokta, çatışma davranışının deyimde yazılmasının, uygulama kodunda “önce sorgula sonra ekle” biçiminde yazılmasından güvenli olmasıdır: sorgu ile ekleme arasında geçen sürede başka bir oturum aynı satırı ekleyebilir.
Eklemenin İşlem İçinde Toplanması
Ekleme deyimlerinin kaç işlem içinde çalıştığı, aynı veriyi yazan iki betiği ayırır. Açık bir işlem başlatılmazsa motor her deyimi kendi işlemi sayar ve her deyimin sonunda kalıcılığı güvenceye almak için diske eşitleme yapar. Yirmi bin deyim, yirmi bin eşitleme demektir.
cd "$(mktemp -d)" satirlar() { awk 'BEGIN { for (i = 1; i <= 20000; i++) printf "INSERT INTO odunc_yuk VALUES (%d, %d, %d, \0472025-03-01\047);\n", i, 1 + i % 7, 1 + i % 6 }' } sema="CREATE TABLE odunc_yuk (odunc_id INTEGER PRIMARY KEY, kitap_id INTEGER NOT NULL, uye_id INTEGER NOT NULL, alis_tarihi TEXT NOT NULL);" { echo "$sema"; satirlar; } > tek_tek.sql { echo "$sema"; echo "BEGIN;"; satirlar; echo "COMMIT;"; } > tek_islem.sql echo "--- her deyim ayri islem ---" time sqlite3 a.db ".read tek_tek.sql" echo "--- hepsi tek islemde ---" time sqlite3 b.db ".read tek_islem.sql" sqlite3 a.db "SELECT count(*) FROM odunc_yuk;" sqlite3 b.db "SELECT count(*) FROM odunc_yuk;"
--- her deyim ayri islem --- real 0m4.323s user 0m0.153s sys 0m3.148s --- hepsi tek islemde --- real 0m0.026s user 0m0.022s sys 0m0.003s 20000 20000
Aynı yirmi bin satır, aynı deyimler, aynı sonuç. Aradaki fark yüzlerce kattır. Ölçüm
diskin ve makinenin özelliklerine bağlıdır — sayılar her çalıştırmada ve her makinede
değişir — ama oranın büyüklüğü, işlem sınırının başarımda ne kadar belirleyici olduğunu
gösterir. awk içindeki \047 yazımı tek tırnak karakterini üretir; kabuk tırnaklamasıyla
çakışmadan SQL dizgisi yazmayı sağlar.
Aynı etkiyi tek deyimde çok satır yazarak da elde etmek olanaklıdır: bin satırlık bir
VALUES listesi zaten tek işlemdir. İki yöntem birlikte kullanılır — toplu deyimler,
açık bir işlemin içinde. İşlem sınırının çok geniş tutulmasının da bir bedeli vardır ve o
konu İleri SQL kursunun kilitleme dersine aittir.
Özet
- Ekleme deyiminin sütun listeli biçimi şema değişikliklerine dayanıklıdır; konumsal biçim sütun sırası değiştiğinde sessizce yanlış sütuna yazabilir.
- Tek deyimde yazılan çok satır bölünmez: satırlardan biri kısıta takılırsa hiçbiri yazılmaz.
INSERT ... SELECTbiçimi veriyi uygulamaya taşımadan tablolar arasında aktarır; eşleme sütun adlarına göre değil sıraya göre yapılır.- Eklenen satırın motor tarafından üretilen değerlerini geri okuma ve çatışma davranışını deyimde belirtme olanağı vardır, ancak yazımı motora göre değişir.
- Eklemeyi açık bir işlemin içinde toplamak, her deyimin ayrı işlem sayılmasına göre ölçülebilir biçimde daha hızlıdır; fark diske eşitleme sayısından gelir.
Sonraki Adım
Veri yerinde. Sonraki ders onu değiştirmeyi ve silmeyi ele alır. UPDATE ve DELETE
deyimlerinin sözdizimi kısadır, tehlikesi ise koşul cümlesinin isteğe bağlı olmasından
gelir: koşulu unutulmuş bir güncelleme sözdizimsel olarak kusursuzdur ve tablodaki her
satırı değiştirir. O dersin çekirdeği, bu deyimleri yazarken çalışan alışkanlıktır —
önce işlem açmak, etkilenen satır sayısını görmek ve gerekirse geri almak.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.