2016-07-15 4 views
1

Это структура таблицы: Id Name ParentIdSQL: Удалить все вложенные самостоятельно REFERENCING записи

ParentId является внешним ключом к первичному столбцу Id. Теперь давайте говорить у меня есть несколько строк, как: (только показывая ParentId из рядов)

 01 
/ \ 
    5  2 
     /\ 
     3 4 

У меня есть настройки InsteadOfDelete триггера, как показано ниже:

CREATE TRIGGER [dbo].[tr_tb] ON [dbo].[Some_tb] 
    INSTEAD OF DELETE 
AS 
    /*Delete from another table*/ 
    DELETE FROM SomeOther_tb WHERE OtherId IN(SELECT Id FROM deleted); 

    /*Delete childs from this table*/ 
    DELETE FROM Some_tb WHERE ParentId IN(SELECT Id FROM deleted); 

    /*Delete from this table*/ 
    DELETE FROM Some_tb WHERE Id IN(SELECT Id FROM deleted); 

При записи с Id = 01 (проверить представление Чайлдс выше) удаляется. Только немедленные дети (Id=5,2) удаляются, оставляя за собой дочерние записи (Id = 3,4).

Я принимаю InsteadOfTrigger Функции не запускаются для детей (Id=5,2).

Как решить эту проблему, чтобы все вложенные дети были удалены?

+1

Почему бы не использовать каскадные удаления, поскольку это похоже на то, что вы делаете? – UnhandledExcepSean

+0

Невозможно из-за множественного каскадного пути: https://www.mssqltips.com/sqlservertip/2733/solving-the-sql-server-multiple-cascade-path-issue-with-a-trigger/ –

+0

Так что это самосоединяющийся стол? – UnhandledExcepSean

ответ

0
DECLARE @DELETED TABLE(
     Id BIGINT 
    ); 


WITH LoopCTE AS (
    SELECT Id, ParentId,0 AS steps 
    FROM dbo.Some_tb 
    WHERE Id IN (SELECT Id FROM deleted) 

    UNION ALL 

    SELECT mgr.Id, mgr.ParentId, parent.steps +1 AS steps 
    FROM LoopCTE AS parent 
    INNER JOIN dbo.Some_tb AS mgr 
     ON parent.Id = mgr.ParentId 
) 
INSERT INTO @DELETED SELECT Id FROM LoopCTE AS u; 

/*Delete from another table*/ 
DELETE FROM SomeOther_tb WHERE OtherId IN(SELECT Id FROM @DELETED); 


/*Delete childs from this table*/ <-- No longer required 
/*DELETE FROM Some_tb WHERE ParentId IN(SELECT Id FROM @DELETED);*/ 

/*Delete from this table*/ 
DELETE FROM Some_tb WHERE Id IN(SELECT Id FROM @DELETED); 
+0

нет необходимости в таблице '@ deleted' –

+0

@AlexKudryashev Затем, как вставить новые идентификаторы, найденные CTE? СОЮЗ с удаленным? –

+0

Вам не нужно ** вставлять ** их. Используйте CTE непосредственно, чтобы «удалить» то, что вы хотите. –

1
CREATE TRIGGER [dbo].[tr_tb] ON [dbo].[Some_tb] 
    INSTEAD OF DELETE 
AS 
    DECLARE @DELETED TABLE(
     ID BIGINT 
    ) 

    INSERT INTO @DELETED 
     SELECT Id FROM deleted 

    --could use a CTE here as well for better performance 
    WHILE @@ROWCOUNT>0 
     BEGIN 
      INSERT INTO @DELETED 
       SELECT Id 
       FROM Some_tb t 
       inner join @DELETED d on d.parentid=t.id 
     END 

    /*Delete from another table*/ 
    DELETE FROM SomeOther_tb WHERE OtherId IN(SELECT Id FROM @DELETED); 

    /*Delete childs from this table*/ 
    DELETE FROM Some_tb WHERE ParentId IN(
     SELECT Id FROM @DELETED WHERE ID NOT IN (SELECT ID FROM DELETED) 
    ); 

    /*Delete from this table*/ 
    DELETE FROM Some_tb WHERE Id IN(SELECT Id FROM DELETED); 
+0

Большое спасибо за ответ. Я попробовал некоторые материалы CTE и написал свой ответ. Понравился бы ваш вклад/предложения. –

1

MS SQL Server 2008 поддерживает Common Table Expressions (CTE), которые являются большими для иерархических данных. И CTE может существовать и в триггерах.

CREATE TRIGGER [dbo].[tr_tb] ON [dbo].[Some_tb] 
    INSTEAD OF DELETE 
AS 
    /*Delete from another table*/ 
    ;with tbl as (--this is CTE 
     --anchor query (top level) 
     select t.id, t.parentid 
     from someOther_tb t 
     inner join deleted d on d.id = t.parentid 
     union all 
     --recursive query 
     select t.id, t.parentid 
     from someOther_tb t 
     inner join tbl on tbl.id=t.parentid 
    ) 
    delete someOther_tb 
    where id in (select id from tbl)   

    --Now it is safe to delete from main table 
    DELETE FROM Some_tb WHERE Id IN(SELECT Id FROM deleted) 
+0

Спасибо Alex, я думаю, 'from someOther_tb' здесь не так, как' ParentId' и 'Id' из одной таблицы. Btw Я добавил ответ с реализацией CTE. Дайте мне знать ваше мнение об этом. –

+0

Вы имеете в виду, что 'some_tb' и' someOther_tb' (как в OP) являются одной и той же таблицей? –

+0

Целью здесь является удаление всех вложенных дочерних элементов 'Some_tb', включая записи из' SomeOther_tb', на которые ссылаются 'Some_tb'. Проблема, описанная в вопросе, заключается в том, что все вложенные дочерние элементы не были удалены. –

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