İçeriğe geç
academia.sh

Ders 04 / 14

Bütünlük Kısıtları

Alan, varlık ve başvuru bütünlüğünün tanımı; yabancı anahtarın silme ve güncelleme eylemleri; kısıt denetiminin zamanlaması ve kısıtın şemaya yazılmasının gerekçesi.

İçindekiler

Önceki ders bir yabancı anahtar ihlalini reddetti ama arkasındaki kuralı adlandırmadı. Bu dersin sorusu şudur: veritabanının her an sağlaması gereken kurallar nelerdir, bu kurallar şemada nasıl yazılır, ve kuralı bozacak bir silme geldiğinde sistemin seçebileceği davranışlar hangileridir?

Kısıtlar üç katmanda toplanır. Alan bütünlüğü (domain integrity) bir sütuna hangi değerlerin yazılabileceğini söyler — tip, NOT NULL ve CHECK bunun araçlarıdır ve önceki derste görüldü. Varlık bütünlüğü (entity integrity) her satırın kimliğinin belirli olmasını ister. Başvuru bütünlüğü (referential integrity) bir bağıntıdan diğerine yapılan başvurunun boşa düşmemesini ister. Dördüncü bir katman, alana özgü iş kurallarıdır; bunlar da mümkün olduğunca şemaya yazılır.

Varlık Bütünlüğü

Kural tek cümledir: birincil anahtarı oluşturan hiçbir sütun boş değer alamaz. Gerekçesi doğrudan anahtarın tanımından gelir. Anahtarın işi satırı ayırt etmektir; boş değer ise “bilinmiyor” demektir. Kimliği bilinmeyen bir satır, kendisine başvurulamayan bir satırdır.

Bu kuralın standartta yazılı olması, her motorun onu aynı sıkılıkta uyguladığı anlamına gelmez:

sqlite3 :memory: <<'SQL'
.headers on
.mode box
CREATE TABLE sube (sube_kodu TEXT PRIMARY KEY, ad TEXT NOT NULL);
INSERT INTO sube VALUES (NULL, 'Adsız Şube');
SELECT COUNT(*) AS satir FROM sube;
SQL
┌───────┐
│ satir │
├───────┤
│ 1     │
└───────┘

Birincil anahtarı boş olan bir satır tabloya girdi. Bu davranış motora göre değişir; kimi motor aynı deyimi reddeder. Taşınabilir ve niyeti açık şema, kuralı kendi yazar:

sqlite3 :memory: <<'SQL'
CREATE TABLE sube (sube_kodu TEXT PRIMARY KEY NOT NULL, ad TEXT NOT NULL);
INSERT INTO sube VALUES (NULL, 'Adsız Şube');
SQL
Runtime error near line 2: NOT NULL constraint failed: sube.sube_kodu (19)

Buradan çıkan genel ilke, kursun tekrar eden temalarından biridir: bir kuralın motorda zaten var olduğunu varsaymak yerine şemada açıkça yazmak, hem taşınabilirliği hem okunabilirliği artırır.

Başvuru Bütünlüğü

Kural şudur: bir yabancı anahtarın değeri ya boştur, ya da başvurduğu bağıntıda o değere sahip bir satır vardır. Üçüncü bir olasılık yoktur; hedefi bulunmayan satıra yetim kayıt (orphan record) denir.

Bu kuralın uygulanıp uygulanmadığı da motora göre değişir. Burada kullanılan komut satırı aracında denetim varsayılan olarak kapalıdır ve oturum başına açılması gerekir:

sqlite3 :memory: <<'SQL'
.headers on
.mode box
PRAGMA foreign_keys;
CREATE TABLE uye (uye_no INTEGER PRIMARY KEY, ad TEXT NOT NULL);
CREATE TABLE odunc (
  odunc_no INTEGER PRIMARY KEY,
  uye_no   INTEGER NOT NULL REFERENCES uye (uye_no)
);
INSERT INTO odunc VALUES (1001, 77);
SELECT COUNT(*) AS yetim_kayit FROM odunc;
SQL
┌──────────────┐
│ foreign_keys │
├──────────────┤
│ 0            │
└──────────────┘
┌─────────────┐
│ yetim_kayit │
├─────────────┤
│ 1           │
└─────────────┘

Şemada REFERENCES yazılıdır, üye tablosu boştur, buna rağmen ödünç kaydı girmiştir. Denetim kapalı olduğu için bildirim yalnızca belgeleme değeri taşımıştır. Bu dersin geri kalanındaki bloklar denetimi açan satırla başlar.

Silme ve Güncelleme Eylemleri

Başvuru bütünlüğü bozulabilecek iki an vardır: başvurulan satır silindiğinde ve başvurulan anahtar değeri güncellendiğinde. Şema, bu iki an için bir davranış seçer.

  • NO ACTION / RESTRICT — işlem reddedilir. Standarttaki varsayılan davranıştır; ikisi arasındaki fark denetimin zamanlamasındadır.
  • CASCADE — silme ya da güncelleme, başvuran satırlara yayılır.
  • SET NULL — başvuran satırın yabancı anahtarı boşaltılır; sütunun boş değer kabul etmesi gerekir.
  • SET DEFAULT — başvuran satırın yabancı anahtarı sütunun öntanımlı değerine çekilir; o değerin hedefte bulunması gerekir.

Seçim keyfî değildir, alanın anlamını izler. Üye silindiğinde onun ceza kayıtlarının kalması anlamsızdır — bunlar üyeye bağımlı, kendi başına var olamayan kayıtlardır, yani CASCADE. Şube kapandığında üyenin kaydı silinmemelidir; üye şubesiz kalır, yani SET NULL. Üyeye ait ödünç geçmişi ise silinmemelidir — geçmiş kayıt bir olgudur — bu yüzden silme reddedilir.

sqlite3 :memory: <<'SQL'
.headers on
.mode box
.nullvalue (bos)
PRAGMA foreign_keys = ON;
CREATE TABLE sube (sube_kodu TEXT PRIMARY KEY NOT NULL, ad TEXT NOT NULL);
CREATE TABLE uye (
  uye_no    INTEGER PRIMARY KEY,
  ad        TEXT NOT NULL,
  sube_kodu TEXT REFERENCES sube (sube_kodu) ON DELETE SET NULL
);
CREATE TABLE ceza (
  ceza_no INTEGER PRIMARY KEY,
  uye_no  INTEGER NOT NULL REFERENCES uye (uye_no) ON DELETE CASCADE,
  tutar   INTEGER NOT NULL
);
INSERT INTO sube VALUES ('MRK', 'Merkez'), ('BHC', 'Bahçelievler');
INSERT INTO uye VALUES (41, 'Ayşe Demir', 'MRK'), (52, 'Mert Kaya', 'BHC');
INSERT INTO ceza VALUES (9001, 52, 30), (9002, 52, 15);
DELETE FROM uye  WHERE uye_no = 52;
DELETE FROM sube WHERE sube_kodu = 'MRK';
SELECT (SELECT COUNT(*) FROM uye)  AS uye_satiri,
       (SELECT COUNT(*) FROM ceza) AS ceza_satiri,
       (SELECT sube_kodu FROM uye WHERE uye_no = 41) AS uye41_sube;
SQL
┌────────────┬─────────────┬────────────┐
│ uye_satiri │ ceza_satiri │ uye41_sube │
├────────────┼─────────────┼────────────┤
│ 1          │ 0           │ (bos)      │
└────────────┴─────────────┴────────────┘

Tek bir üye silindi ve ona bağlı iki ceza kaydı da gitti; şube silindi ve ona bağlı üye şubesiz kaldı. .nullvalue ayarı, boş değeri çıktıda görünür kılmak içindir — ayar verilmediğinde boş değer ile boş dizgi ekranda ayırt edilemez.

Öntanımlı davranış ise reddetmektir:

sqlite3 :memory: <<'SQL'
PRAGMA foreign_keys = ON;
CREATE TABLE uye (uye_no INTEGER PRIMARY KEY, ad TEXT NOT NULL);
CREATE TABLE odunc (
  odunc_no INTEGER PRIMARY KEY,
  uye_no   INTEGER NOT NULL REFERENCES uye (uye_no)
);
INSERT INTO uye VALUES (41, 'Ayşe Demir');
INSERT INTO odunc VALUES (1001, 41);
DELETE FROM uye WHERE uye_no = 41;
SQL
Runtime error near line 9: FOREIGN KEY constraint failed (19)

CASCADE seçiminde dikkatli olmak gerekir: yayılma zincirlenir. Üyeyi silen bir deyim, ona bağlı ceza kayıtlarını, onlara bağlı ödeme kayıtlarını ve bu zincirin devamını da siler. Silinen satır sayısı, deyimi yazanın gördüğünden çok daha büyük olabilir.

Kısıt Ne Zaman Denetlenir

Kısıtlar öntanımlı olarak her deyimin sonunda denetlenir. Bu, bazı doğru durumların geçici olarak kurulamamasına yol açar. İki bağıntı birbirine karşılıklı başvuruyorsa — her şubenin bir yöneticisi vardır ve her yönetici bir şubede çalışır — hangisi önce eklenirse eklensin, ekleme anında karşı taraf henüz yoktur.

Çözüm, denetimi işlemin sonuna ertelemektir; buna ertelenmiş kısıt (deferred constraint) denir. Ertelenmiş denetimde ara durumlar kuralı bozabilir, yeter ki işlem tamamlandığında kural sağlansın. Bu yeteneğin bulunup bulunmadığı ve nasıl bildirildiği motora göre değişir; bulunmayan motorlarda karşılıklı başvurunun bir ucunun boş değer kabul etmesi ve iki adımda doldurulması gerekir.

Kısıtı Nereye Yazmalı

Her kural şemaya sığmaz. “Bir üye aynı anda en çok beş nüsha ödünç alabilir” kuralı, tek satıra bakarak denetlenemez; sayım gerektirir. Böyle kurallar ya bir tetikleyiciyle ya da uygulama katmanında yazılır.

Ölçüt şudur: kural veriye erişen bütün yollar için geçerliyse ve tek bir satır ya da satır kümesi üzerinden ifade edilebiliyorsa şemaya yazılır. Şemadaki kısıt, hangi programın yazdığından, hangi dilde yazıldığından ve veriye elle mi yoksa toplu göçle mi dokunulduğundan bağımsız olarak uygulanır. Uygulama katmanındaki denetim yalnızca o uygulamadan geçen yazmaları kapsar; ikinci bir servis, bir bakım betiği ya da elle çalıştırılan bir deyim onu atlar.

Kısıtın ikinci işlevi belgelemedir. Şemayı okuyan biri, ON DELETE CASCADE yazan bir satırdan ceza kaydının üyeye bağımlı olduğunu okur. Aynı bilgi uygulama kodunda dağınık biçimde durduğunda okunmaz.

Özet

  • Varlık bütünlüğü birincil anahtarın boş değer alamamasıdır; kimliği belirsiz satıra başvurulamaz.
  • Başvuru bütünlüğü, yabancı anahtarın ya boş olmasını ya da hedefte karşılığı bulunmasını ister; ihlali yetim kayıt üretir.
  • Motorun bir kuralı öntanımlı olarak uyguladığını varsaymak yerine kısıtı şemada açıkça yazmak taşınabilirliği ve okunabilirliği artırır.
  • Silme ve güncelleme eylemleri — reddetme, yayma, boşaltma, öntanımlıya çekme — alanın anlamına göre seçilir; yayma zincirlenerek beklenenden çok satır siler.
  • Bütün yazma yollarını bağlayan ve satır düzeyinde ifade edilebilen kurallar şemaya, sayım ya da geçmiş gerektirenler uygulama katmanına yazılır.

Sonraki Adım

Bu derste iki kez “ya boştur” ifadesi geçti: yabancı anahtar boş olabilir, SET NULL sütunu boşaltır. Boş değerin ne anlama geldiği ise tanımlanmadı. Sıradaki ders, boş değerin bir değer olmadığını, karşılaştırmaların onunla ne yaptığını ve doğru–yanlış ikilisine üçüncü bir sonucun eklenmesinin sorgu yazımında hangi tuzakları açtığını 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