2009-02-09 57 views
9

Có đúng là MS SQL hạn chế các ràng buộc tự tham chiếu với tùy chọn ON DELETE CASCADE không? Tôi có một bảng có quan hệ cha-con, cột PARENT_ID là khóa ngoài cho ID. Tạo ra nó với ON DELETE tùy chọn CASCADE gây lỗiRàng buộc tự tham chiếu trong MS SQL

"Giới thiệu FOREIGN KEY constraint có thể gây ra chu kỳ hoặc nhiều thác đường dẫn. Chỉ ON DELETE không có hành động hoặc ON UPDATE KHÔNG HÀNH ĐỘNG, hoặc sửa đổi ràng buộc khoá ngoại khác. "

Tôi không thể tin rằng tôi phải xóa phân cấp này trong chế độ đệ quy. Có bất kỳ vấn đề nào ngoại trừ trình kích hoạt không?

Trả lời

9

Đó là trường hợp bạn không thể thiết lập BẬT DELETE CASCADE trên bảng có ràng buộc tự tham chiếu. Có một tiềm năng của các vấn đề logic theo chu kỳ, do đó nó sẽ không cho phép nó.

Có một bài viết hay here - mặc dù nó dành cho phiên bản 8 thay vì 9 của SQL - mặc dù các quy tắc tương tự được áp dụng.

+0

PostgreSQL hỗ trợ nó. Bây giờ nếu một mục khác không bị xóa tham chiếu đến một tệp con sẽ bị xóa, nó sẽ phát hành một lỗi và thao tác xóa sẽ được khôi phục. Nếu không, nó sẽ hoạt động hoàn hảo. Vấn đề thực sự là, cho dù mối quan hệ cha-con của bạn là một đồ thị theo hướng không tuần hoàn hay không. Bởi vì hầu hết các tài liệu tham khảo tự thực hiện phân cấp, và các hệ thống phân cấp nên được định hướng theo các biểu đồ không tuần hoàn, quá trình hành động của PostgreSQL sẽ trở nên lành mạnh hơn trong hầu hết các trường hợp. Trong tất cả các trường hợp khác, bạn vẫn có thể thực hiện chức năng đó theo cách thủ công, vì vậy không có gì bị mất. –

0
CREATE TRIGGER MyTable_OnDelete ON MyTable 
INSTEAD OF DELETE 
AS 
BEGIN 

    SET NOCOUNT ON; 

    DELETE FROM mt 
    FROM deleted AS D 
    JOIN MyTable AS mt 
    ON  d.Id = mt.ParentId 

    DELETE FROM mt 
    FROM deleted AS D 
    JOIN MyTable AS mt 
    ON  d.Id = mt.Id 

END 
+0

Xin lỗi nhưng trong một trường hợp nếu 'MyTable' có quan hệ với một bảng khác (có' ON DELETE CASCADE ... '), bạn không thể xác định kích hoạt' INSTEAD OF DELETE' ... – Bellash

4

Tôi chỉ trả lời another question nơi câu hỏi này được ràng buộc như trùng lặp. Tôi nghĩ rằng cũng đáng để đặt câu trả lời của tôi ở đây:

Điều này là không thể. Bạn có thể giải quyết việc này với một INSTEAD OF TRIGGER

create table locations 
(
    id int identity(1, 1), 
    name varchar(255) not null, 
    parent_id int, 

    constraint pk__locations 
     primary key clustered (id) 

) 
GO 

INSERT INTO locations(name,parent_id) VALUES 
('world',null) 
,('Europe',1) 
,('Asia',1) 
,('France',2) 
,('Paris',4) 
,('Lyon',4); 
GO 

--This kích hoạt sẽ sử dụng một CTE đệ quy để có được tất cả các ID sau tất cả id bạn đang xóa. Các ID này sẽ bị xóa.

CREATE TRIGGER dbo.DeleteCascadeLocations ON locations 
INSTEAD OF DELETE 
AS 
BEGIN 
    WITH recCTE AS 
    (
     SELECT id,parent_id 
     FROM deleted 

     UNION ALL 

     SELECT nxt.id,nxt.parent_id 
     FROM recCTE AS prv 
     INNER JOIN locations AS nxt ON nxt.parent_id=prv.id 
    ) 
    DELETE FROM locations WHERE id IN(SELECT id FROM recCTE); 
END 
GO 

--Test it here, thử với các ID khác nhau. Bạn có thể thử WHERE id IN(4,3) cũng ...

SELECT * FROM locations; 

DELETE FROM locations WHERE id=4; 

SELECT * FROM locations 
GO 

--Clean-Up (cẩn thận với dữ liệu thực tế!)

if exists(select 1 from INFORMATION_SCHEMA.TABLES where TABLE_NAME='locations') 
---DROP TABLE locations; 
+0

Tôi có một bảng tự tham chiếu đến ba cấp độ sâu, đã thử nghiệm rộng rãi với điều này và nó hoạt động hoàn hảo. Cảm ơn bạn rất nhiều! – vaindil

Các vấn đề liên quan