2016-07-15 64 views
1

這是一個表的結構:Id Name ParentIdSQL:刪除所有嵌套自參照記錄

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

「@刪除」表中沒有必要使用 –

+0

@AlexKudryashev然後如何插入已被CTE發現的新'Ids'?聯盟與刪除? –

+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支持通用表表達式(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

謝謝亞歷克斯,我猜'從someOther_tb'不正確,因爲'ParentId'和'Id'來自同一張表。順便說一句,我添加了CTE實現的答案。請讓我知道你對此的看法。 –

+0

你的意思是'some_tb'和'someOther_tb'(如OP)是同一張表嗎? –

+0

此處的目的是刪除'Some_tb'的所有嵌套子元素,包括'SomeOther_tb'中用'Some_tb'引用的記錄。 問題所描述的問題是所有嵌套的孩子沒有被刪除。 –