2010-03-03 40 views
5

Tôi có một bảng SQL được định nghĩa như sau:Khóa chính Composite và lỗi ràng buộc khoá ngoại

CREATE TABLE [TestComposite] ( 
    ID int, 
    SiteUrl nvarchar(255), 
    Name nvarchar(max) NOT NULL, 
    ParentID int NULL, 
    PRIMARY KEY (ID, SiteUrl) 
); 

mục và thư mục được lưu trữ bên trong cùng một bảng, nếu một mục nằm bên trong một thư mục, cột ParentID là ID của thư mục. Và tôi muốn có thể xóa các mục/thư mục CASCADE khi tôi xóa một thư mục.

Một ví dụ có thể rõ ràng hơn:

INSERT INTO [TestComposite] VALUES (1, 'site1', 'Item1', NULL) 
INSERT INTO [TestComposite] VALUES (2, 'site1', 'Item2', NULL) 
INSERT INTO [TestComposite] VALUES (3, 'site1', 'Folder1', NULL) 
INSERT INTO [TestComposite] VALUES (4, 'site1', 'Folder1.Item1', 3) 
INSERT INTO [TestComposite] VALUES (5, 'site1', 'Folder1.Item2', 3) 
INSERT INTO [TestComposite] VALUES (6, 'site1', 'Folder1.Folder1', 3) 
INSERT INTO [TestComposite] VALUES (7, 'site1', 'Folder1.Folder1.Item1', 6) 
etc... 

Vì vậy, nếu chúng ta xóa mục 3 (thư mục), tôi muốn các mục/thư mục 4, 5, 6 và 7 để bị xóa quá.

Tôi cố gắng thêm một hạn chế tương tự như:

ALTER TABLE [TestComposite] 
ADD CONSTRAINT fk_parentid 
FOREIGN KEY (ParentID, SiteUrl) 
REFERENCES [TestComposite] (ID, SiteUrl) ON DELETE CASCADE; 

Nhưng nó mang lại cho tôi lỗi này:
Giới thiệu ràng buộc khoá ngoại 'fk_parentid' trên bảng 'TestComposite' có thể gây ra chu kỳ hoặc nhiều đường thác. Chỉ định ON DELETE NO ACTION hoặc ON UPDATE NO ACTION, hoặc sửa đổi các ràng buộc KEY NGOẠI HỐI khác.

Tôi cũng đã cố gắng thêm cột SiteUrl thứ hai có tên ParentSiteUrl, trong trường hợp vấn đề là một cột không phải là một phần của cùng một FK/PK, nhưng tôi có cùng thông báo lỗi.

Tôi đang làm gì sai?

Cảm ơn bạn,

Trả lời

5

Tạo một ràng buộc ON DELETE NO ACTION và sử dụng này để xóa tất cả hồ sơ và con cái của họ:

WITH q AS 
     (
     SELECT id, SiteURL 
     FROM TestComposite 
     WHERE id = 3 
       AND SiteURL = 'site1' 
     UNION ALL 
     SELECT tc.id, tc.SiteURL 
     FROM q 
     JOIN TestComposite tc 
     ON  tc.ParentID = q.Id 
       AND tc.SiteURL = q.SiteURL 
     ) 
DELETE 
FROM TestComposite 
WHERE EXISTS 
     (
     SELECT id, SiteURL 
     INTERSECT 
     SELECT * 
     FROM q 
     ) 
+0

Tôi có thể sai vì tôi chưa thử nghiệm, nhưng tôi không nghĩ rằng nó sẽ xóa mục 7 trong trường hợp của tôi, vì nó ở cấp độ khác của hệ thống phân cấp ?! –

+0

'@ OmaR': có nó cũng sẽ xóa' 7'. Đó là một 'CTE' đệ quy. – Quassnoi

+0

Cảm ơn bạn, nó hoạt động tuyệt vời. Tôi không biết về CTE đệ qui. Và có vẻ như nó hoạt động trên cả SQL Server 2005 và SQL Server 2008. –

0

Tôi nghĩ rằng những gì bạn muốn làm có thể đạt được bằng cách thêm một cột mới có tên gọi ParentId, và sau đó khai báo nó như chính nước ngoài với khóa chính. Bằng cách đó, vấn đề sẽ được giải quyết và bạn vẫn có thể thực hiện mọi thứ bạn muốn

+0

Xin lỗi, tôi không hiểu những gì bạn sẽ muốn tôi làm gì ?! –

0

Vấn đề là bạn tạo khả năng thác tầng đệ quy - mỗi khi bị xóa bởi thác có thể tạo ra bất kỳ số lần xóa tiếp theo nào. MS SQL không hỗ trợ nó. Cố gắng xóa chúng trong mã của bạn theo cách thủ công. BTW tôi không khuyên bạn nên xóa tầng.

http://support.microsoft.com/kb/321843

+0

Như tôi đã nói với Ardman, nếu tôi không có một khóa chính tổng hợp, chỉ nói ID, tôi sẽ có thể tạo ra một khóa ngoại đệ quy mà không có vấn đề gì. TẠO BIỂU TƯỢNG myTable (ID int PRIMARY KEY, Tên nvarchar (tối đa), ParentID int); ALTER TABLE myTable THÊM LỆNH fk_parentID KEY NGOÀI (ParentID) TÀI LIỆU THAM KHẢO myTable (ID) TRÊN TRƯỜNG HỢP XÓA; Không?! –

+0

không, bạn không thể! Tôi chỉ cố gắng. nó không phải là về khóa tổng hợp hay không, đó là về bạn có thể tạo một đệ quy trên tầng và máy chủ sql không muốn tự làm nó – Andrey

+0

Thật lạ lùng, tôi thề là tôi đã làm điều đó ... Tôi sẽ kiểm tra lại :) –

1

Nếu bạn có SQL Server 2008, sử dụng từ HierarchyID loại cho công tác này.

+0

Cảm ơn bạn, tôi sẽ thử này –

+0

OmaR chào mừng của bạn. –

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