İçeriğe geç
academia.sh

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

  • UPDATE ve DELETE deyimlerinde 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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat