คำอธิบายที่ดีเกี่ยวกับพฤติกรรมแบบเรียงซ้อน (ON DELETE / UPDATE)


98

ฉันไม่ได้ออกแบบสกีมาทุกวัน แต่เมื่อฉันทำฉันพยายามตั้งค่าการปรับปรุง / ลบทั้งหมดอย่างถูกต้องเพื่อให้การจัดการง่ายขึ้น ฉันเข้าใจว่าน้ำตกมีประโยชน์อย่างไร แต่ฉันจำไม่ได้ว่าตารางใดอยู่

ตัวอย่างเช่นถ้าฉันมีสองตาราง - ParentและChild- มีคีย์ต่างประเทศในChildการอ้างอิงนั้นParentและมีON DELETE CASCADEบันทึกใดที่ทำให้เกิดน้ำตกและบันทึกใดถูกลบโดยน้ำตก? การเดาครั้งแรกของฉันจะเป็นChildระเบียนที่ถูกลบเมื่อParentบันทึกถูกลบเนื่องจากChildระเบียนขึ้นอยู่กับParentระเบียน แต่สิ่งที่ON DELETEคลุมเครือนั้น มันอาจหมายถึงลบParentบันทึกเมื่อChildบันทึกถูกลบหรืออาจหมายถึงลบChildบันทึกเมื่อParentถูกลบ แล้วมันคืออะไร?

ฉันหวังว่าไวยากรณ์เป็นON PARENT DELETE, CASCADE, ON FOREIGN DELETE, CASCADEหรือสิ่งที่คล้ายกันในการลบความคลุมเครือ ใครบ้างมีความจำในการจดจำสิ่งนี้?

คำตอบ:


138

หากคุณต้องการParentและChildข้อกำหนดและคุณรู้สึกว่าพวกเขาเป็นเรื่องง่ายที่จะจำได้ว่าคุณอาจต้องการการแปลของON DELETE CASCADEการLeave No Orphans!

ซึ่งหมายความว่าเมื่อParentแถวถูกลบ (ฆ่า) ไม่ควรมีแถวเด็กกำพร้าอยู่ในChildตาราง เด็กทุกคนในแถวพาเรนต์ถูกฆ่า (ลบ) ด้วย หากเด็กเหล่านี้คนใดคนหนึ่งมีหลาน (ในตารางอื่นผ่านกุญแจต่างประเทศอื่น) และมีการON DELETE CASCADEกำหนดไว้พวกเขาควรจะถูกฆ่าเช่นกัน (และลูกหลานทั้งหมดตราบใดที่มีการกำหนดเอฟเฟกต์น้ำตก)

FOREIGN KEYจำกัด ตัวเองยังสามารถอธิบายได้ว่าAllow No Orphans!(ในสถานที่แรก) ไม่Childควรได้รับอนุญาต (เขียน) ในตารางลูกถ้าไม่ได้Parent(แถวในตารางหลัก)

เพื่อความสอดคล้องกันON DELETE RESTRICTสามารถแปลเป็น (น้อย aggresive) You Can't Kill Parents!เฉพาะแถวที่ไม่มีลูกเท่านั้นที่สามารถฆ่าได้ (ลบแล้ว)


3
ฉันรู้สึกว่าบางสิ่งยังขาดหายไปในการเปรียบเทียบ เด็กมีพ่อหรือแม่มากกว่าหนึ่งคนหรือไม่? ในกรณีนี้จะฆ่าผู้ปกครองคนหนึ่งทำให้เด็กกำพร้า?
Jus12

7
@ Jus12 ไม่ข้อ จำกัด ของ foreign key ทำงานร่วมกับ 1 parent เท่านั้น มันไม่ได้เป็นการเปรียบเทียบที่ดีเกี่ยวกับแง่มุมนี้
ypercubeᵀᴹ

1
@ypercube: ไม่อนุญาตหรือไม่ Order(custID, itemID, orderID)โดยcustIDอ้างอิงถึงคีย์หลักในCustomersตารางและitemIDอ้างถึงคีย์หลักในItemsตาราง Orderพ่อแม่ทั้งสองจะไม่ได้เหรอ?
Jus12

4
@ Jus12 ที่ได้รับอนุญาตแน่นอน แต่มันจะเป็นข้อ จำกัด ที่สำคัญต่างประเทศ 2 จากนั้นเด็กทุกคน (คำสั่งซื้อ) จะมีผู้ปกครอง (ลูกค้า) และผู้ปกครอง (รายการ) พฤติกรรมของ 2 FKs อาจแตกต่างกัน (ตัวอย่างเช่นอาจเป็นได้ว่าการฆ่าลูกค้าจะฆ่าเด็ก (คำสั่งซื้อ) ทั้งหมด แต่การฆ่าไอเท็มจะไม่ฆ่าคำสั่งซื้อของพวกเขา)
ypercubeᵀᴹ

1
การเปรียบเทียบผู้ปกครองยังคงสามารถทำงานได้หากเราไม่พูดว่า "เด็กกำพร้า" หากมีการอ้างอิงสองรายการถึงผู้ปกครองที่แยกกันสองคนในรายการลูกสิ่งนี้ยังสามารถเห็นได้ว่าเป็นลูกของคู่ที่หย่าร้าง จำกัด : "ฉันจะไม่ปล่อยให้คุณฆ่าแม่ของฉัน" น้ำตก: "ถ้าคุณฆ่าพ่อของฉันฉันก็จะตาย"
Christopher McGowan

31

ตัวอย่างเช่นถ้าฉันมีสองตาราง - ผู้ปกครองและเด็ก - ที่บันทึกลูกเป็นเจ้าของโดยบันทึกผู้ปกครองตารางใดที่ต้องการในการลบทั้งหมดหรือไม่

ON DELETE CASCADE เป็นอนุประโยคที่เป็นทางเลือกในการประกาศคีย์ foreign ดังนั้นมันจะไปกับการประกาศคีย์ต่างประเทศ (ความหมายในตาราง "ลูก")

... มันอาจหมายถึงลบระเบียนผู้ปกครองเมื่อมีการลบระเบียนเด็กหรืออาจหมายถึงลบบันทึกย่อยเมื่อผู้ปกครองถูกลบ แล้วมันคืออะไร?

วิธีหนึ่งในการตีความการประกาศคีย์ต่างประเทศคือ "ค่าที่ถูกต้องทั้งหมดสำหรับคอลัมน์นี้มาจาก 'that_column' ใน 'that_table' เมื่อคุณลบแถวในตาราง "ลูก" ไม่มีใครสนใจ ไม่ส่งผลกระทบต่อความถูกต้องของข้อมูล

เมื่อคุณลบแถวออกจากตาราง "พาเรนต์" - จาก "that_table" - คุณลบค่าที่ถูกต้องออกจากค่าที่เป็นไปได้สำหรับตาราง "ลูก" เพื่อรักษาความถูกต้องของข้อมูลคุณต้องทำอะไรบางอย่างกับตาราง "ลูก" การลบเรียงซ้อนเป็นสิ่งหนึ่งที่คุณสามารถทำได้


2

SQL: ข้อมูลจำเพาะ 2011

มีห้าตัวเลือกสำหรับการมีON DELETEและที่สามารถนำไปใช้กับON UPDATE FOREIGN KEYสิ่งเหล่านี้ถูกเรียก<referential actions>โดยตรงจากข้อมูลจำเพาะของ SQL: 2011

  • ON DELETE CASCADE: หากแถวของตารางอ้างอิงถูกลบออกแถวที่ตรงกันทั้งหมดในตารางอ้างอิงจะถูกลบ
  • ON DELETE SET NULL: หากแถวของตารางอ้างอิงถูกลบออกคอลัมน์อ้างอิงทั้งหมดในแถวที่ตรงกันทั้งหมดของตารางอ้างอิงจะถูกตั้งค่าเป็น null
  • ON DELETE SET DEFAULT: หากแถวของตารางอ้างอิงถูกลบออกคอลัมน์อ้างอิงทั้งหมดในแถวที่ตรงกันทั้งหมดของตารางอ้างอิงจะถูกตั้งค่าเป็นค่าเริ่มต้นของคอลัมน์
  • ON DELETE RESTRICT: ห้ามลบแถวของตารางอ้างอิงถ้าแถวนั้นมีแถวที่ตรงกันในตารางอ้างอิง
  • ON DELETE NO ACTION (ค่าเริ่มต้น) : ไม่มีการลบการอ้างอิง ข้อ จำกัด การอ้างอิงจะระบุการตรวจสอบข้อ จำกัด เท่านั้น

foreign key สร้างความสัมพันธ์ที่ต้องพึ่งพากัน <referential action>กำหนดสิ่งที่เกิดขึ้นเมื่อความสัมพันธ์จะละลาย

ตัวอย่าง / อุปมา / คำอธิบาย

สำหรับตัวอย่างนี้เราจะยอมรับรูปแบบทั่วไปของสังคมและเศรษฐกิจ: ที่ทุกbusinessเป็น บริษัท ที่มีความสัมพันธ์ที่จะได้ผ่านbourgeoisiefatcat_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');

ถ้าทุกคนbusinessได้รับผลกระทบโดยตรงbourgeoisieจากวิธีการของพวกเขาfatcat_ownerคุณจะทำอย่างไรหลังจากการปฏิวัติของคนงานเมื่อคุณกำจัดคนfatcat_ownerและมีสังคมที่ไร้ชนชั้น?

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

คุณมีตัวเลือกน้อยที่นี่

  • หยุดการปฏิวัติ ใน SQL RESTRICTพูดจา บางคนเชื่อว่านี่เป็นความชั่วร้ายที่น้อยกว่า แต่พวกเขามักผิด
  • ปล่อยให้มันดำเนินต่อไป ถ้าเป็นเช่นนั้นเมื่อการปฏิวัติเกิดขึ้น SQL ให้สี่ตัวเลือก

    • SET NULL- ปล่อยว่างไว้ ใครจะรู้บางทีทุนนิยมถูกบูรณะbourgeoisieขึ้นมาและ oligarchs fatcat_ownersกรอกม้วนของ หมายเหตุสำคัญคอลัมน์จะต้องเป็นNULLABLE(ไม่ใช่NOT NULL) ไม่เช่นนั้นจะไม่เกิดขึ้น
    • SET DEFAULT- บางทีคุณอาจมีสิ่งDEFAULTที่จัดการเรื่องนี้? DEFAULTสามารถเรียกฟังก์ชั่น บางทีสคีมาของคุณพร้อมที่จะปฏิวัติแล้ว
    • CASCADE- ไม่มีการควบคุมความเสียหาย ถ้าbourgeoisieไปก็ทำbusinessเช่นนั้น หากธุรกิจต้องมี a fatcat_pigดังนั้นบางครั้งมันก็สมเหตุสมผลที่จะสูญเสียข้อมูลแทนที่จะมีธุรกิจที่ไม่ใช่ธุรกิจในbusinessตาราง
    • NO ACTION- นี่เป็นวิธีการหน่วงเวลาการตรวจสอบใน MySQL มันไม่แตกต่างจากRESTRICTแต่ใน PostgreSQL คุณสามารถทำได้

      -- 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;

      ในระบบดังกล่าวข้อ จำกัด จะได้รับการตรวจสอบก่อนทำรายการเท่านั้น ซึ่งอาจส่งผลให้หยุดการปฏิวัติ แต่คุณสามารถกู้คืนในการทำธุรกรรม - สำหรับ "กู้คืน" ในระดับหนึ่ง


ไม่referencedตารางหมายถึงตารางแม่และreferencingตารางหมายถึงตารางเด็ก?
sg552

@ sg552 ใช่คุณเข้าใจถูกต้อง
informatik01

0

ช่วยในการจำง่าย ๆ

ON DELETE ของผู้ปกครองทั้งหมด [โดยการลบ] ที่นี่

ที่บอกคุณว่าการลบใด (การลบพาเรนต์) ถูกเรียงซ้อนซึ่งคำสั่งON DELETE CASCADEไปที่ (บน child) และสิ่งที่ถูกลบ (child)


-3

ดีบางทีเราสามารถหาเหตุผลเข้าข้างตนเองไวยากรณ์ ลองทำตัวอย่าง 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)

สิ่งที่บรรทัดนี้บอกว่าเป็น on_delete ของผู้ปกครอง (ซึ่งถูกกล่าวถึงโดยไม่ตั้งใจในคำสั่ง) โปรดเรียงซ้อนการลบลงในเด็ก นั่นคือเหตุผลที่คำสั่ง CASCADE ถูกกำหนดที่ระดับลูกมันเป็นเครื่องหมายลูกที่ต้องลบ

ตัวอย่างเช่นถ้าคุณมีชั้นเรียนอื่น

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

โครงสร้างนี้จะแสดงให้เห็นอย่างชัดเจนว่าเด็กคนไหนที่จะต้องถูกลบ (เด็ก) และที่จะอยู่ (GrownUpChild) แม้ว่าเด็กกำพร้า

[แก้ไข: ตามบริบทของการสนทนาโดยเฉพาะในกรณีของ on_delete = models.CASCADE ฯลฯ ] ในความเป็นจริงมันมักจะเป็นพฤติกรรมที่ต้องการให้ลูกของผู้ปกครองที่ถูกลบเนื่องจากการตรวจสอบและการรายงานเหตุผลเช่นเดียวกับการกู้คืนโดยไม่ตั้งใจ ลบ [แน่นอนซอฟต์แวร์ระดับองค์กรจะถูกสร้างขึ้นรอบ ๆ พฤติกรรมดังกล่าวและจะตั้งค่าสถานะบันทึกที่ถูกลบเป็นลบ = 1 แทนที่จะลบทิ้งจริงและจะไม่รวมไว้ในแบบสอบถามใด ๆ สำหรับส่วนหน้าด้วยลบบางรายงานที่ออกแบบมาเป็นพิเศษ นอกจากนี้ยังมีฟังก์ชั่นในการลบบันทึก == 1 ที่ถูกลบออกจากฐานข้อมูลซึ่งโดยปกติแล้วจะถูกดำเนินการโดยผู้ดูแลระบบ UI ซึ่งมักจะหลีกเลี่ยงการมีส่วนร่วมจากด้านข้างของผู้ดูแลระบบฐานข้อมูล]


1
'ในความเป็นจริงมันมักจะเป็นพฤติกรรมที่ต้องการให้ลูกของผู้ปกครองที่ถูกลบเนื่องจากการตรวจสอบและการรายงานเหตุผลเช่นเดียวกับการกู้คืนการลบโดยไม่ตั้งใจ' - ที่จะหายนะในฐานข้อมูล (สติ)
dezso

@dezso ขอบคุณสำหรับการป้อนข้อมูลของคุณ อย่างไรก็ตามระบบ CRM ระดับองค์กรหลายอย่างนั้น
George Mogilevsky

TBH ที่ไม่ทำให้เข้าใจได้ง่ายขึ้น ฉันเคยได้รับมอบหมายให้แก้ไขอึที่เกิดจากวิธีการดังกล่าว - ไม่มีความสุขยกเว้น paycheck
dezso

คุณเสียงเหมือนผู้ดูแลฐานข้อมูลที่เข้าใจ :) ฉันได้ยินจุดของคุณทั้งหมด ซอฟต์แวร์ที่ฉันกล่าวถึงข้างต้นนั้นใช้งานได้จริงมีฟังก์ชั่นเพื่อลบไฟล์ที่ถูกลบ = 1 ด้วยตนเองดังนั้นจึงขึ้นอยู่กับผู้ดูแลระบบของแอปที่จะโทรออกนี้ โดยปกติผู้ดูแลระบบฐานข้อมูลไม่ได้มีส่วนร่วมในการดูแลด้านนี้ และนอกจากนี้ระดับฐานข้อมูลซอฟต์แวร์ทั้งหมดถูกสร้างขึ้นรอบแนวคิดจึงจะตรวจสอบธงที่ถูกลบในการดำเนินงาน CRUD
จอร์จ Mogilevsky

ใช่นั่นเป็นรูปแบบที่เป็นที่รู้จักและมีสติ แต่คุณควรเปลี่ยนถ้อยคำข้างต้นเพื่อสะท้อนสิ่งนี้
dezso
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.