Penjelasan yang baik tentang perilaku kaskade (ON DELETE / UPDATE)

98

Saya tidak merancang skema setiap hari, tetapi ketika saya melakukannya, saya mencoba untuk mengatur pembaruan / penghapusan kaskade dengan benar untuk membuat administrasi lebih mudah. Saya mengerti bagaimana kaskade bekerja, tetapi saya tidak pernah ingat tabel mana yang mana.

Sebagai contoh, jika saya memiliki dua tabel - Parentdan Child- dengan kunci asing pada Childreferensi itu Parentdan memiliki ON DELETE CASCADE, catatan mana yang memicu kaskade dan catatan mana yang bisa dihapus oleh kaskade? Dugaan pertama saya adalah Childrekaman yang dihapus ketika Parentcatatan dihapus, karena Childcatatan bergantung pada Parentcatatan, tetapi ON DELETEambigu; itu bisa berarti menghapus Parentcatatan ketika Childcatatan dihapus, atau itu bisa berarti menghapus Childcatatan ketika Parentdihapus. Jadi yang mana?

Saya berharap sintaksnya ON PARENT DELETE, CASCADE, ON FOREIGN DELETE, CASCADEatau sesuatu yang serupa untuk menghapus ambiguitas. Adakah yang punya mnemonik untuk mengingat ini?

Johntron
sumber

Jawaban:

138

Jika Anda suka Parentdan Childterm dan Anda merasa mudah diingat, Anda mungkin ingin terjemahan dari ON DELETE CASCADEkeLeave No Orphans!

Yang berarti bahwa ketika sebuah Parentbaris dihapus (terbunuh), tidak ada baris yatim yang harus tetap hidup di Childtabel. Semua anak dari baris induk juga terbunuh (dihapus). Jika salah satu dari anak-anak ini memiliki cucu (di meja lain melalui kunci asing lain) dan ada yang ON DELETE CASCADEdidefinisikan, ini harus dibunuh juga (dan semua keturunan, selama ada efek kaskade yang ditentukan.)

The FOREIGN KEYkendala itu sendiri juga dapat digambarkan sebagai Allow No Orphans!(di tempat pertama). Tidak Childboleh diizinkan (tertulis) di tabel anak jika tidak memiliki Parent(baris di tabel induk).

Untuk konsistensi, ON DELETE RESTRICTdapat diterjemahkan ke (kurang agresif) You Can't Kill Parents!Hanya baris tanpa anak yang dapat dibunuh (dihapus.)

ypercubeᵀᴹ
sumber
3
Saya merasa ada sesuatu yang hilang dalam analogi ini. Tidak bisakah seorang anak memiliki lebih dari satu orang tua? Dalam hal ini akankah membunuh satu orangtua membuat anak menjadi yatim?
Jus12
7
@ Jus12 Tidak, batasan kunci asing hanya berfungsi dengan 1 orang tua. Ini bukan analogi yang baik tentang aspek ini.
ypercubeᵀᴹ
1
@ ypercube: Apakah ini tidak diizinkan? Order(custID, itemID, orderID)di mana custIDmengacu pada kunci utama dalam Customerstabel dan itemIDmengacu pada kunci utama dalam Itemstabel. Tidak akan Ordermemiliki dua orang tua?
Jus12
4
@ Jus12 Itu diperbolehkan tentu saja tetapi itu akan menjadi 2 batasan kunci asing. Maka setiap anak (pesanan) akan memiliki orang tua (pelanggan) dan orang tua (barang). Perilaku 2 FK mungkin berbeda. (Jadi, misalnya, bisa jadi membunuh pelanggan akan membunuh semua (pesanan) anak-anak mereka tetapi membunuh barang tidak akan membunuh pesanan mereka.)
ypercubec
1
Analogi orang tua masih bisa berfungsi jika kita tidak mengatakan "yatim". Jika ada dua referensi ke dua orang tua yang terpisah pada entri anak, ini masih dapat dilihat sebagai anak dari pasangan yang bercerai. Batasi: "Aku tidak akan membiarkanmu membunuh ibuku" Cascade: "Jika kau membunuh ayahku, aku juga akan mati"
Christopher McGowan
31

Misalnya, jika saya memiliki dua tabel - Induk dan Anak - di mana catatan Anak dimiliki oleh catatan Induk, tabel mana yang memerlukan ON DELETE CASCADE?

ON DELETE CASCADE adalah klausa opsional dalam deklarasi kunci asing. Begitu pula dengan deklarasi kunci asing. (Artinya, dalam tabel "anak".)

... itu bisa berarti menghapus catatan Orang Tua ketika catatan Anak dihapus, atau itu bisa berarti menghapus catatan Anak ketika Orang Tua dihapus. Jadi yang mana?

Salah satu cara untuk menafsirkan deklarasi kunci asing adalah, "Semua nilai yang valid untuk kolom ini berasal dari 'that_column' di 'that_table'." Saat Anda menghapus baris di tabel "anak", tidak ada yang peduli. Itu tidak mempengaruhi integritas data.

Saat Anda menghapus baris dari tabel "parent" - from "that_table" - Anda menghapus nilai yang valid dari nilai yang mungkin untuk tabel "child". Untuk menjaga integritas data, Anda harus melakukan sesuatu pada tabel "child". Menghapus Cascading adalah satu hal yang bisa Anda lakukan.

Mike Sherrill 'Cat Recall'
sumber
2

SQL: 2011 Spec

Ada lima opsi untuk ON DELETE, dan ON UPDATEitu bisa berlaku untuk FOREIGN KEY. Ini disebut <referential actions>, langsung dari SQL: 2011 spec

  • ON DELETE CASCADE: jika baris dari tabel referensi dihapus, maka semua baris yang cocok di tabel referensi dihapus.
  • ON DELETE SET NULL: jika baris dari tabel referensi dihapus, maka semua kolom referensi di semua baris yang cocok dari tabel referensi harus disetel ke nol.
  • ON DELETE SET DEFAULT: jika baris dari tabel referensi dihapus, maka semua kolom referensi di semua baris yang cocok dari tabel referensi harus diatur ke nilai default kolom.
  • ON DELETE RESTRICT: itu dilarang untuk menghapus baris dari tabel yang direferensikan jika baris itu memiliki baris yang cocok di tabel referensi.
  • ON DELETE NO ACTION (default) : tidak ada tindakan penghapusan referensial; batasan referensial hanya menentukan pemeriksaan kendala.

Kunci asing menetapkan hubungan dependen. Yang <referential action>menentukan apa yang terjadi ketika hubungan dibubarkan.

Contoh / Metafora / Penjelasan

Untuk contoh ini, kami akan menerima model umum dari masyarakat dan ekonomi: di mana setiap businessperusahaan adalah perusahaan yang memelihara hubungan bourgeoisiemelalui fatcat_owner.

CREATE TABLE bourgeoisie(
  fatcat_owner varchar(100) PRIMARY KEY
);
INSERT INTO bourgeoisie(fatcat_owner) VALUES
  ( 'Koch Brothers' );

CREATE TABLE business (
  name         varchar(100),
  fatcat_owner varchar(100) REFERENCES bourgeoisie
);
INSERT INTO business(name, fatcat_owner)
  VALUES ('Georgia-Pacific', 'Koch Brothers');

Jika semua orang businesssecara langsung dipengaruhi oleh bourgeoisiecara mereka fatcat_ownermaka apa yang Anda lakukan setelah revolusi pekerja ketika Anda membersihkan fatcat_ownerdan memiliki masyarakat tanpa kelas?

-- Viva la revolución 
BEGIN;
  DELETE FROM bourgeoisie;
END;

Anda memiliki beberapa opsi di sini,

  • Hentikan revolusi. Dalam bahasa SQL RESTRICT,. Beberapa orang percaya ini adalah kejahatan yang lebih rendah, tetapi mereka biasanya salah.
  • Biarkan terus. Jika demikian ketika revolusi terjadi SQL memberi Anda empat opsi,

    • SET NULL- biarkan kosong. Siapa tahu, mungkin kapitalisme dipulihkan yang bourgeoisiemuncul dan kaum oligarki mengisi daftar fatcat_owners. Catatan penting, kolom harus NULLABLE(tidak NOT NULL) atau ini tidak akan pernah terjadi.
    • SET DEFAULT- mungkin Anda punya DEFAULTyang menangani ini? A DEFAULTdapat memanggil suatu fungsi. Mungkin skema Anda sudah siap untuk revolusi.
    • CASCADE- tidak ada kontrol kerusakan. Jika bourgeoisieberjalan, begitu juga dengan business. Jika suatu bisnis harus memiliki fatcat_pig, maka kadang-kadang lebih masuk akal kehilangan data daripada memiliki non-bisnis dalam sebuah businesstabel.
    • NO ACTION- ini pada dasarnya adalah metode untuk menunda pemeriksaan, di MySQL tidak ada bedanya RESTRICT, tetapi di PostgreSQL, Anda dapat melakukannya

      -- Not a real revolution.
      -- requires constraint be DEFERRABLE INITIALLY DEFERRED
      BEGIN;
        SET CONSTRAINTS ALL DEFERRED;
        DELETE FROM bourgeoisie;
        INSERT INTO bourgeoisie VALUES ( 'Putin' );
        UPDATE business SET fatcat_pig = 'Putin';
      END;

      Dalam sistem seperti itu, kendala divalidasi hanya sebelum transaksi dilakukan. Ini dapat mengakibatkan penghentian revolusi, tetapi Anda dapat memulihkan dalam transaksi - untuk beberapa tingkat "pulih."

Evan Carroll
sumber
Apakah referencedtabel berarti tabel induk dan referencingtabel berarti tabel anak?
sg552
@ sg552 Ya, Anda memahaminya dengan benar.
informatik01
0

Mnemonik sederhana adalah

HAPUS orangtua CASCADE [dengan menghapus] di sini

Itu memberitahu Anda yang menghapus (menghapus dari orang tua) yang mengalir, di mana pernyataan ON DELETE CASCADE berjalan (pada anak), dan apa yang akan dihapus (anak).

msouth
sumber
-3

yah, mungkin kita bisa merasionalisasi sintaks. Mari kita ambil contoh Python:

class Parent(self):
    # define parent's fields

class Child(self):    
    # define child's fields
    parent_pk_is_childs_foreign_key = models.ForeignKey(Parent, on_delete=models.CASCADE)

apa yang baris ini katakan adalah on_delete of the Parent (yang secara tidak sengaja disebutkan dalam pernyataan), silakan cascade penghapusan ke anak. Itulah sebabnya pernyataan CASCADE didefinisikan di tingkat anak, itu menandai anak-anak yang perlu dihapus

Misalnya jika Anda memiliki kelas lain

class GrownUpChild(self):    
        # define grown up child's fields
        parent_pk_is_childs_foreign_key = models.ForeignKey(Parent, on_delete=models.DO_NOTHING)

struktur ini akan dengan jelas menunjukkan yang mana dari anak-anak perlu dihapus (Anak) dan yang akan tinggal (Orang Dewasa) meskipun yatim piatu

[Sunting: Mengingat konteks diskusi, khususnya dalam kasus on_delete = models.CASCADE dll,] sebenarnya sering kali merupakan perilaku yang diinginkan untuk meninggalkan anak-anak dari orang tua yang dihapus, karena alasan audit dan pelaporan, serta memulihkan ketidaksengajaan. penghapusan. [tentu saja perangkat lunak tingkat perusahaan akan dibangun di sekitar perilaku tersebut dan akan menandai catatan yang dihapus sebagai yang dihapus = 1 bukannya benar-benar menghapusnya dan juga tidak akan memasukkannya dalam kueri untuk ujung depan, dikurangi beberapa laporan yang dirancang khusus. Selain itu ia akan memiliki fungsi membersihkan catatan == 1 yang dihapus dari database, yang biasanya akan dieksekusi oleh administrator UI, sering kali menghindari keterlibatan dari sisi administrator database.]

George Mogilevsky
sumber
1
'Sebenarnya seringkali merupakan perilaku yang diinginkan untuk meninggalkan anak-anak dari orang tua yang dihapus, karena alasan audit dan pelaporan, serta memulihkan penghapusan yang tidak disengaja' - yang akan menjadi bencana dalam database (waras).
dezso
@dezso terima kasih atas masukan Anda. Namun, beberapa sistem CRM tingkat perusahaan melakukan hal itu.
George Mogilevsky
TBH yang tidak membuatnya lebih masuk akal. Saya pernah mendapat tugas untuk memperbaiki omong kosong yang dihasilkan dari pendekatan semacam itu - tidak ada sukacita, kecuali gaji.
dezso
Anda terdengar seperti admin database yang cerdas :) Saya benar-benar dapat mendengar maksud Anda. Perangkat lunak yang saya sebutkan di atas yang melakukannya, sebenarnya memiliki fungsi untuk menghapus yang dihapus = 1 secara manual sehingga terserah admin aplikasi untuk melakukan panggilan ini. Biasanya administrator basis data bahkan tidak terlibat dalam memelihara aspek ini. Dan selain itu, seluruh kelas basis data perangkat lunak dibangun di sekitar konsep, sehingga selalu memeriksa tanda yang dihapus dalam operasi kasar
George Mogilevsky
Ya, itu adalah pola yang dikenal dan waras - tetapi kemudian Anda mungkin harus mengubah kata-kata di atas untuk mencerminkan hal ini.
dezso