2010-03-03 16 views
5

ich eine SQL-Tabelle, wie unten definiert habe:Composite-Primärschlüssel und Fremdschlüssel Einschränkungsfehler

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

Elemente und Ordner in der gleichen Tabelle gespeichert werden, wenn ein Element in einem Ordner ist, ist die ParentID Spalte des ID des Ordners Und ich würde gerne in der Lage sein, CASCADE Elemente/Ordner zu löschen, wenn ich einen Ordner lösche.

kann ein Beispiel deutlicher sein:

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

Also, wenn ich den Artikel 3 (ein Ordner) löschen, möchte ich die Elemente/Ordner 4, 5, 6 und 7 zu streichen.

Ich habe versucht, eine Einschränkung ähnlich wie hinzuzufügen:

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

Aber es gibt mir diese Fehlermeldung:
FOREIGN KEY-Einschränkung Introducing ‚fk_parentid‘ auf dem Tisch ‚TestComposite‘ Zyklen oder mehrere Kaskadenwege verursachen können. Geben Sie ON DELETE NO ACTION oder ON UPDATE NO ACTION an, oder ändern Sie andere FOREIGN KEY-Einschränkungen.

Ich habe auch versucht, eine zweite SiteUrl-Spalte namens ParentSiteUrl, falls das Problem war, dass eine Spalte nicht Teil der gleichen FK/PK sein sollte, aber ich habe die gleiche Fehlermeldung.

Mache ich etwas falsch?

Danke,

Antwort

5

eine ON DELETE NO ACTION Einschränkung dieser erstellen und verwenden, um alle Aufzeichnungen und ihre Kinder zu löschen:

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

Ich mag mich irren, da ich es noch nicht getestet habe, aber ich glaube nicht, dass es das Element 7 in meinem Fall löschen würde, da es auf einer anderen Ebene der Hierarchie ist?! –

+0

'@ OmaR': ja es wird' 7' auch löschen. Es ist ein rekursives 'CTE'. – Quassnoi

+0

Danke, es funktioniert super. Ich wusste nichts über rekursive CTE. Und es scheint, dass es auf SQL Server 2005 und SQL Server 2008 funktioniert. –

0

Ich denke, was Sie durch das Hinzufügen einer neuen Spalte namens ParentId erzielte tun wollen werden kann und es dann als Fremdschlüssel mit Primärschlüssel deklarieren. So wird das Problem gelöst und Sie können immer noch alles tun

+0

Sorry, ich verstehe nicht, was würden Sie wollen, dass ich tun ?! –

0

Das Problem ist, dass Sie die Möglichkeit der rekursiven Kaskade erstellen - wenn jede durch Kaskade gelöscht kann eine beliebige Anzahl von nachfolgenden Löschungen erstellen. MS SQL unterstützt es nicht. Versuchen Sie, sie manuell in Ihrem Code zu löschen. BTW Ich empfehle nicht Kaskadenlöschungen.

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

+0

Wie ich Ardman sagte, wenn ich keinen zusammengesetzten Primärschlüssel habe, sage nur ID, wäre ich in der Lage, einen rekursiven Fremdschlüssel ohne Problem zu erstellen. CREATE TABLE MeineTabelle (ID int PRIMARY KEY, Name nvarchar (max), ParentID int); ALTER TABLE myTable HINZUFÜGEN CONSTRAINT fk_parentID FOREIGN KEY (ParentID) REFERENZEN myTable (ID) ON CASCADE DELETE; Nein?! –

+0

Nein, du kannst nicht! Ich habe es versucht. es geht nicht um Composite-Schlüssel oder nicht, es geht darum, Sie können eine Rekursion auf Kaskade erstellen und SQL-Server will es nicht selbst tun – Andrey

+0

Das ist komisch, ich würde schwören, ich habe das bereits gemacht ... Ich werde es erneut testen :) –

1

Wenn Sie SQL Server 2008, verwenden Sie von HierarchyID Typ für diese Arbeit.

+0

Vielen Dank, ich werde dieses –

+0

Ihre Willkommen OmaR versuchen. –

Verwandte Themen