Ders 16 / 18
Güncelleme ve Silme
UPDATE ve DELETE deyimlerinin yapısı, koşul cümlesi unutulduğunda ne olduğu, etkilenen satır sayısının okunması, işlem açıp geri alma alışkanlığı ve silmenin bağlı satırlara etkisi.
İçindekiler
Veri tabloya girdi. Sıradaki iki deyim onu değiştirir ve siler. Sözdizimleri kursun en
kısa deyimleri arasındadır; tehlikeleri de tam olarak buradan gelir. WHERE cümlesi
isteğe bağlıdır — yani koşulu unutulmuş bir güncelleme sözdizimsel olarak kusursuzdur,
motor tarafından uyarısız kabul edilir ve tablodaki her satırı değiştirir.
Bu dersin bütün örnekleri :memory: veritabanında çalışır: bellekte kurulan, komut
bitince yok olan geçici bir veritabanı. Yıkıcı bir deyimin ne yaptığını görmenin yolu onu
çalıştırmaktır, ancak çalıştırılacağı yer gerçek veri değildir.
Koşullu Güncelleme
UPDATE deyimi üç parçadan oluşur: hangi tablo, hangi sütunlara hangi değerler, hangi
satırlar. Üçüncü parça yazılmazsa “hangi satırlar” sorusunun yanıtı “hepsi” olur.
sqlite3 :memory: <<'SQL' .headers on .mode column CREATE TABLE uye ( uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL, durum TEXT NOT NULL DEFAULT 'etkin' CHECK (durum IN ('etkin', 'askida', 'kapali')) ); INSERT INTO uye VALUES (1,'Ayşe','Demir','etkin'),(2,'Mehmet','Kaya','etkin'), (3,'Zeynep','Arslan','askida'),(4,'Emre','Yıldız','etkin'); SELECT uye_id, ad, soyad FROM uye WHERE uye_id = 2; UPDATE uye SET durum = 'askida' WHERE uye_id = 2; SELECT changes() AS etkilenen; SELECT * FROM uye; SQL
uye_id ad soyad ------ ------ ----- 2 Mehmet Kaya etkilenen --------- 1 uye_id ad soyad durum ------ ------ ------ ------ 1 Ayşe Demir etkin 2 Mehmet Kaya askida 3 Zeynep Arslan askida 4 Emre Yıldız etkin
Blokta iki alışkanlık gömülü. Birincisi, güncellemeden önce aynı koşulla bir SELECT
çalıştırmaktır: hangi satırların etkileneceği önce görülür. İkincisi, güncellemeden sonra
etkilenen satır sayısını okumaktır. Beklenen sayı biliniyorsa — burada bir — sapma anında
fark edilir.
Güncelleme kısıtları atlamaz. durum sütununa listede olmayan bir değer yazan bir
güncelleme, ekleme sırasındakiyle aynı CHECK hatasını üretir. Şemadaki kısıtlar yazma
yollarının tamamında geçerlidir.
Koşulun Unutulması
Aşağıdaki blok, koşulu olmayan bir güncellemenin ne yaptığını gösterir. Deyimin kendisi
bir öncekiyle aynıdır, yalnızca WHERE cümlesi yoktur.
sqlite3 :memory: <<'SQL' .headers on .mode column CREATE TABLE uye ( uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL, durum TEXT NOT NULL DEFAULT 'etkin' CHECK (durum IN ('etkin', 'askida', 'kapali')) ); INSERT INTO uye VALUES (1,'Ayşe','Demir','etkin'),(2,'Mehmet','Kaya','etkin'), (3,'Zeynep','Arslan','askida'),(4,'Emre','Yıldız','etkin'); UPDATE uye SET durum = 'askida'; SELECT changes() AS etkilenen; SELECT * FROM uye; SQL
etkilenen --------- 4 uye_id ad soyad durum ------ ------ ------ ------ 1 Ayşe Demir askida 2 Mehmet Kaya askida 3 Zeynep Arslan askida 4 Emre Yıldız askida
Dört satır. Hata yok, uyarı yok, onay sorusu yok. Kütüphanenin bütün üyeleri askıya
alındı ve bunu söyleyen tek şey changes() çıktısındaki sayıdır.
Zararın ölçeği tablonun büyüklüğüyle orantılıdır. Dört satırlık bir örnekte sonuç bir saniyede görülür; dört yüz bin satırlık bir üye tablosunda, eski değerlerin nerede tutulduğu sorusuna dönüşür. Eski değerler hiçbir yerde tutulmaz — güncelleme yerinde yapılır. Geri dönüş yolu yedekten kurtarmadır ve o da yedeğin alındığı ana kadardır.
Aynısı silme için de geçerlidir ve orada daha keskindir: koşulsuz bir DELETE, tablonun
bütün satırlarını kaldırır.
Geri Alınabilir Alışkanlık
Bu riskin karşılığı dikkat değil, yordamdır. Yazma deyimi açık bir işlemin içinde çalıştırılır; etkilenen satır sayısı okunur; sayı beklendiği gibiyse işlem kesinleştirilir, değilse geri alınır.
sqlite3 :memory: <<'SQL' .headers on .mode column CREATE TABLE uye ( uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL, durum TEXT NOT NULL DEFAULT 'etkin' ); INSERT INTO uye VALUES (1,'Ayşe','Demir','etkin'),(2,'Mehmet','Kaya','etkin'), (3,'Zeynep','Arslan','askida'),(4,'Emre','Yıldız','etkin'); BEGIN; UPDATE uye SET durum = 'askida'; SELECT changes() AS etkilenen; ROLLBACK; SELECT * FROM uye; SQL
etkilenen --------- 4 uye_id ad soyad durum ------ ------ ------ ------ 1 Ayşe Demir etkin 2 Mehmet Kaya etkin 3 Zeynep Arslan askida 4 Emre Yıldız etkin
Aynı koşulsuz güncelleme çalıştı, aynı dört satırı etkiledi, sonra ROLLBACK deyimi
hepsini geri aldı. Tablo işlem öncesindeki hâlindedir: üçüncü üye askıda, diğerleri etkin.
BEGIN ile başlayan bir işlem, COMMIT görene kadar kalıcı değildir. Bu, elle yazılan
her yazma deyiminin varsayılan çerçevesi olmalıdır. Deyim doğruysa COMMIT, sayı
şaşırtıcıysa ROLLBACK yazılır — ve şaşırtıcı sayıyı görme fırsatı ancak işlem açıkken
vardır.
İşlemlerin ayrıntısı — yalıtım düzeyleri, kilitleme, kısmi geri alma — İleri SQL kursunun konusudur. Burada gereken tek şey çerçevedir.
Koşulu Sorgudan Almak
Güncellenecek satırlar bir sorgunun sonucuyla belirlenebilir. Bu, “iade edilmemiş ve tarihi geçmiş ödüncü olan üyeleri askıya al” gibi kuralları tek deyimde yazmayı sağlar.
sqlite3 :memory: <<'SQL' .headers on .mode column CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL, durum TEXT NOT NULL DEFAULT 'etkin'); 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 uye VALUES (1,'Ayşe','Demir','etkin'),(2,'Mehmet','Kaya','etkin'), (3,'Zeynep','Arslan','etkin'); INSERT INTO odunc VALUES (1, 1, 1, '2024-11-01', NULL), (2, 2, 2, '2025-06-01', NULL), (3, 3, 3, '2024-12-15', '2025-01-02'); BEGIN; UPDATE uye SET durum = 'askida' WHERE uye_id IN (SELECT uye_id FROM odunc WHERE iade_tarihi IS NULL AND alis_tarihi < '2025-01-01'); SELECT changes() AS etkilenen; COMMIT; SELECT * FROM uye; SQL
etkilenen --------- 1 uye_id ad soyad durum ------ ------ ------ ------ 1 Ayşe Demir askida 2 Mehmet Kaya etkin 3 Zeynep Arslan etkin
Yalnızca birinci üye askıya alındı: ikincinin ödüncü açık ama tarihi yeni, üçüncününki eski ama iade edilmiş. Alt sorgu her iki koşulu birlikte uyguladı.
Bu yazımın sınanabilir olması bir yan yarardır: alt sorgu, güncellemeden önce tek başına
SELECT olarak çalıştırılabilir ve hangi kimliklerin döndüğü görülür. Alt sorguların
ayrıntılı ele alınışı İleri SQL kursuna aittir; burada kullanımı koşul yazmakla sınırlıdır.
Silme ve Bağlı Satırlar
DELETE deyiminin yapısı daha da kısadır: hangi tablo ve hangi satırlar.
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,'2023-01-10','2023-01-24'), (2,2,1,'2023-02-02','2023-02-20'), (3,1,2,'2025-02-11',NULL), (4,3,3,'2025-03-01','2025-03-15'); DELETE FROM odunc WHERE iade_tarihi IS NOT NULL AND iade_tarihi < '2024-01-01'; SELECT changes() AS silinen; DELETE FROM odunc; SELECT changes() AS silinen; SELECT count(*) AS kalan FROM odunc; SQL
silinen ------- 2 silinen ------- 2 kalan ----- 0
İkinci deyimde koşul yoktu ve tablo boşaldı. Bu yüzden silme deyimleri, güncellemeden de
sıkı bir yordamla yazılır: önce koşulun SELECT count(*) ile sayılması, sonra işlem
içinde silme.
Bir satırın silinmesi ona bağlı satırları da ilgilendirir. Yabancı anahtar tanımına eklenen davranış, motorun ne yapacağını belirler. Kısıtlayıcı davranışta silme reddedilir.
sqlite3 :memory: <<'SQL' .headers on .mode column PRAGMA foreign_keys = ON; CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL); CREATE TABLE odunc ( odunc_id INTEGER PRIMARY KEY, kitap_id INTEGER NOT NULL, uye_id INTEGER NOT NULL REFERENCES uye(uye_id) ON DELETE RESTRICT, alis_tarihi TEXT NOT NULL ); INSERT INTO uye VALUES (1,'Ayşe','Demir'),(2,'Mehmet','Kaya'); INSERT INTO odunc VALUES (1,1,1,'2025-02-11'); DELETE FROM uye WHERE uye_id = 1; DELETE FROM uye WHERE uye_id = 2; SELECT changes() AS silinen; SELECT * FROM uye; SQL
Runtime error near line 14: FOREIGN KEY constraint failed (19) silinen ------- 1 uye_id ad soyad ------ ---- ----- 1 Ayşe Demir
Ödüncü olan üye silinemedi, olmayan silindi. Yayılan davranışta ise bağlı satırlar da kaldırılır.
sqlite3 :memory: <<'SQL' .headers on .mode column PRAGMA foreign_keys = ON; CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL); CREATE TABLE odunc ( odunc_id INTEGER PRIMARY KEY, kitap_id INTEGER NOT NULL, uye_id INTEGER NOT NULL REFERENCES uye(uye_id) ON DELETE CASCADE, alis_tarihi TEXT NOT NULL ); INSERT INTO uye VALUES (1,'Ayşe','Demir'),(2,'Mehmet','Kaya'); INSERT INTO odunc VALUES (1,1,1,'2025-01-10'),(2,2,1,'2025-02-02'),(3,1,2,'2025-02-11'); DELETE FROM uye WHERE uye_id = 1; SELECT changes() AS silinen_uye; SELECT * FROM odunc; SQL
silinen_uye ----------- 1 odunc_id kitap_id uye_id alis_tarihi -------- -------- ------ ----------- 3 1 2 2025-02-11
Tek bir üye silindi, onunla birlikte iki ödünç kaydı da gitti. Etkilenen satır sayısı
yine 1 yazıyor: sayaç, deyimin doğrudan hedeflediği tabloya bakar, yayılan silmeleri
saymaz. Yayılan davranışın seçilmesi, ödünç geçmişinin üyeyle birlikte yok olmasını göze
almak demektir. Kütüphane kayıtları gibi geçmişin değerli olduğu alanlarda satır silmek
yerine kaydı kapalı işaretlemek — üyeye kapali durumu vermek — daha uygun bir tasarımdır.
Özet
UPDATEveDELETEdeyimlerinde koşul cümlesi isteğe bağlıdır; yazılmadığında deyim tablodaki bütün satırları etkiler ve motor uyarı vermez.- Etkilenen satır sayısı her yazma deyiminden sonra okunur; beklenen sayıdan sapma, yanlış koşulun tek erken göstergesidir.
- Elle yazılan yazma deyimleri işlem içinde çalıştırılır: sayı doğruysa kesinleştirilir, değilse geri alınır.
- Güncellenecek satırlar bir alt sorguyla belirlenebilir; alt sorgu, deyimden önce tek başına çalıştırılarak sınanır.
- Silmenin bağlı satırlara etkisi yabancı anahtar tanımında yazılır; yayılan silme geçmişi de götürdüğü için, kayıtların değerli olduğu alanlarda kapatma tercih edilir.
Sonraki Adım
Buraya kadarki deyimler tabloların üzerinde doğrudan çalıştı. Sonraki ders araya bir katman koyar: sorgunun kendisine ad vererek tablo gibi kullanılan görünümler. Görünüm veriyi çoğaltmaz, sorguyu saklar — ve bu da ilginç bir soruyu doğurur: bir görünüme satır eklenebilir mi, güncellenebilir mi. Yanıtı görünümün nasıl tanımlandığına ve motora bağlıdır; o dersin bir bölümü bunu deneyerek gösterir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.