Necromancing
คำตอบที่ถูกต้องคือขึ้นอยู่กับเอ็นจิ้นฐานข้อมูลและเครื่องมือการจัดการใด
ลองทำตัวอย่าง:
เรามีตารางรายงาน
และรายงานสามารถมีพาเรนต์ (Menupoint เช่นหมวดหมู่)
และผู้ปกครองนั้นสามารถมีผู้ปกครองได้ (เช่นศูนย์กำไร)
และอื่น ๆ เพื่อโฆษณา
ตัวอย่างที่ง่ายที่สุดของความสัมพันธ์แบบเรียกซ้ำมาตรฐานเช่นเดียวกับเอนทิตี / ลำดับชั้นที่อ้างอิงตัวเอง
ตาราง SQL-Server ที่ได้คือ:
IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'dbo.FK_T_FMS_Reports_T_FMS_Reports') AND parent_object_id = OBJECT_ID(N'dbo.T_FMS_Reports'))
ALTER TABLE dbo.T_FMS_Reports DROP CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.T_FMS_Reports') AND type in (N'U'))
DROP TABLE dbo.T_FMS_Reports
GO
CREATE TABLE dbo.T_FMS_Reports
(
RE_UID uniqueidentifier NOT NULL
,RE_RE_UID uniqueidentifier NULL
,RE_Text nvarchar(255) NULL
,RE_Link nvarchar(400) NULL
,RE_Sort int NOT NULL
,RE_Status int NOT NULL
,PRIMARY KEY CLUSTERED ( RE_UID )
);
GO
ALTER TABLE dbo.T_FMS_Reports WITH CHECK ADD CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports FOREIGN KEY(RE_RE_UID)
REFERENCES dbo.T_FMS_Reports (RE_UID)
-- ON DELETE CASCADE -- here, MS-SQL has a problem
GO
ALTER TABLE dbo.T_FMS_Reports CHECK CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports
GO
แต่คุณได้รับปัญหา:
เมื่อคุณต้องการลบ Menupoint ที่มีเมนูย่อยทั้งหมดคุณไม่สามารถตั้งค่า delete-cascade ได้เนื่องจากMicrosoft SQL-Serverไม่รองรับการลบแบบเรียกซ้ำ (ในทางกลับกัน PostGreSQL จะทำ แต่ถ้า กราฟไม่ได้เป็นวัฏจักร] ในขณะที่ MySQL ไม่ชอบโครงสร้างตารางแบบนี้เลยเพราะมันไม่รองรับ CTE แบบเรียกซ้ำ)
ดังนั้นคุณต้องใช้ความสามารถในการลบ / ความสมบูรณ์ในการทำงานด้วยจึงทำให้จำเป็นต้องใช้ฟังก์ชันดังกล่าวในรหัสของคุณเองหรือในขั้นตอนการจัดเก็บ (หาก RDBMS ของคุณรองรับขั้นตอนการจัดเก็บ)
สิ่งนี้จะไม่มีข้อสงสัยใด ๆ ที่ทำให้เกิดการนำเข้า / ส่งออกข้อมูลแบบไดนามิกอัตโนมัติเต็มรูปแบบเนื่องจากคุณไม่สามารถเรียกใช้คำสั่งลบสำหรับตารางทั้งหมดตามความสัมพันธ์กับคีย์ต่างประเทศ (ไม่ใช่การอ้างอิงตัวเอง) และคุณสามารถเลือกได้ง่าย * และสร้างส่วนแทรกสำหรับทุกแถวตามลำดับโดยพลการ
ตัวอย่างเช่นเมื่อคุณสร้างสคริปต์ INSERT โดยใช้ SSMS แล้ว SSMS จะไม่ได้รับคีย์ต่างประเทศและดังนั้นจึงสร้างคำสั่งแทรกที่จะแทรกรายการที่มีการอ้างอิงก่อนที่มันจะแทรกผู้ปกครองของการพึ่งพาซึ่งจะล้มเหลวด้วยข้อผิดพลาด เนื่องจากมีรหัสต่างประเทศเข้าที่
อย่างไรก็ตามในระบบการจัดการฐานข้อมูลที่เหมาะสม (เช่น PostgreSQL) ด้วยการใช้เครื่องมือที่เหมาะสมสิ่งนี้ไม่ควรเป็นปัญหา เพียงแค่แยกแยะว่าเพราะคุณจ่าย RDBMS ให้มาก (ฉันกำลังมองหาคุณ Microsoft; Oracle =?) และ / หรือแถบเครื่องมือมันไม่ได้หมายความว่ามันถูกตั้งโปรแกรมอย่างถูกต้อง และ OpenSource (เช่น MySQL) ก็ไม่ได้ทำให้คุณมีภูมิคุ้มกันต่อมินิเทียที่ยอดเยี่ยมเช่นนั้น
ปีศาจอยู่ในรายละเอียดตามที่พูดเก่าไป
ตอนนี้ไม่ใช่ว่าคุณไม่สามารถแก้ไขปัญหาดังกล่าวได้ แต่ฉันจะไม่แนะนำถ้าระบบของคุณจะซับซ้อน (เช่น 200+ ตาราง)
นอกจากนี้ในการตั้งค่าเชิงพาณิชย์ตามปกติ (ตามภาพโดย Dilbert) คุณจะไม่ได้รับเวลานั้น
วิธีที่ดีกว่านี้ถึงแม้ว่าจะยากกว่านั้นก็คือตารางปิด
ที่จะมีโบนัสเพิ่มที่มันยังทำงานบน MySQL
เมื่อคุณใช้งานฟังก์ชันการปิดหนึ่งครั้งคุณจะสามารถใช้งานได้ในหลาย ๆ สถานที่โดยไม่ต้องเสียเวลาเลย