2009-02-09 4 views
9

Верно ли, что MS SQL ограничивает ограничения для саморегуляции с опцией ON DELETE CASCADE? У меня есть таблица с отношением parent-child, столбец PARENT_ID - это внешний ключ для ID. Создание его с ON DELETE каскадный вызывает ошибкуОграничение саморегуляции в MS SQL

«Вводя FOREIGN KEY ограничение может вызвать циклов или несколько каскадно пути. Укажите значение ON не DELETE NO ACTION или ON UPDATE NO ACTION или модифицируют другие FOREIGN KEY ограничений. "

Я не могу поверить, что мне нужно удалить эту иерархию в рекурсивном режиме. Есть ли проблема, кроме триггеров?

ответ

9

Это не тот случай, когда вы не можете установить DELETE CASCADE на стол с ограничениями для саморегуляции. Существует потенциал циклических логических задач, поэтому он этого не позволит.

Есть хорошая статья here - хотя это для версии 8, а не для 9 SQL - хотя применяются те же правила.

+0

PostgreSQL поддерживает его. Теперь, если другая запись, которая не должна быть удалена, ссылается на сущность, которая должна быть удалена, она выдаст ошибку, и операция удаления будет отменена. В противном случае он будет работать отлично. Реальная проблема заключается в том, является ли ваше отношение parent-child нециклическим ориентированным графом или нет. Поскольку большинство самоидентификаций реализуют иерархии, а иерархии должны быть направлены нециклическими графами, в большинстве случаев курс действий PostgreSQL будет более разумным. Во всех остальных случаях вы все равно можете реализовать эту функцию вручную, поэтому ничего не потеряно. –

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

Извините, но в одном случае, если 'MyTable' находится в связи с другой таблицей (с' ON DELETE CASCADE ... '), вы не можете определить триггер' INSTEAD OF DELETE' ... – Bellash

4

Я просто ответил another question где этот вопрос был связан как дубликат. Я думаю, что стоит поместить мой ответ и здесь:

Это невозможно. Вы можете решить эту проблему с помощью 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 будет использовать рекурсивный КТР, чтобы получить все идентификаторы следующих все идентификаторы, которые Вы удаляете. Эти идентификаторы удаляются.

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 

- Попробуйте его здесь, попробуйте с разными идентификаторами. Вы можете попробовать WHERE id IN(4,3) также ...

SELECT * FROM locations; 

DELETE FROM locations WHERE id=4; 

SELECT * FROM locations 
GO 

--clean-Up (CAREFULL с реальными данными!)

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

У меня есть таблица, которая ссылается на три уровня в глубину, провел обширные испытания с этим, и он отлично работает. Спасибо огромное! – vaindil

Смежные вопросы