Составные первичные ключи и ошибка ограничения внешнего ключа - PullRequest
5 голосов
/ 03 марта 2010

У меня есть таблица SQL, определенная ниже:

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

Элементы и папки хранятся в одной и той же таблице. Если элемент находится в папке, столбец ParentID является идентификатором папки. И я хотел бы иметь возможность удалять элементы / папки CASCADE при удалении папки.

Пример может быть более явным:

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

Поэтому, если я удаляю элемент 3 (папку), я хочу, чтобы также были удалены элементы / папки 4, 5, 6 и 7.

Я пытался добавить ограничение, похожее на:

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

Но это дает мне эту ошибку:
Введение ограничения FOREIGN KEY 'fk_parentid' в таблицу 'TestComposite' может вызвать циклы или несколько каскадных путей. Укажите ON DELETE NO ACTION или ON UPDATE NO ACTION или измените другие ограничения FOREIGN KEY.

Я также попытался добавить второй столбец SiteUrl с именем ParentSiteUrl, если проблема заключалась в том, что столбец не может быть частью того же FK / PK, но у меня такое же сообщение об ошибке.

Я что-то не так делаю?

Спасибо,

Ответы [ 4 ]

6 голосов
/ 03 марта 2010

Создайте ограничение ON DELETE NO ACTION и используйте его для удаления всех записей и их дочерних элементов:

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
        )
1 голос
/ 03 марта 2010

Если у вас SQL Server 2008, используйте для этой работы тип HierarchyID .

0 голосов
/ 03 марта 2010

Проблема в том, что вы создаете возможность рекурсивного каскада - когда каждый удаленный каскадом может создать любое количество последующих удалений. MS SQL не поддерживает это. Попробуйте удалить их в своем коде вручную. Кстати, я не рекомендую каскадные удаления.

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

0 голосов
/ 03 марта 2010

Я думаю, что то, что вы хотите сделать, может быть достигнуто путем добавления нового столбца с именем ParentId, а затем объявить его как внешний ключ с первичным ключом. Таким образом, проблема будет решена, и вы все равно сможете делать все, что хотите

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...