İçeriğe geç
academia.sh

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 ... SELECT biç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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat