SQL:删除所有嵌套的自引用记录

SQL:删除所有嵌套的自引用记录,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,这是表的结构:Id Name ParentId ParentId是主列Id的外键。现在让我们假设我有几行,如:仅显示来自行的ParentId 01 / \ 5 2 / \ 3 4 我已设置为取代Delete触发器,如下所示: CREATE TRIGGER [dbo].[tr_tb] ON [dbo].[Some_tb] INSTEAD OF DELETE AS /*Delete from another

这是表的结构:Id Name ParentId

ParentId是主列Id的外键。现在让我们假设我有几行,如:仅显示来自行的ParentId

     01
   /    \
  5      2
        / \
       3   4
我已设置为取代Delete触发器,如下所示:

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的子记录

我假设childs Id=5,2时不会触发InsteadOfTrigger函数


如何解决此问题,以便删除所有嵌套的子对象

MS SQL Server 2008支持通用表表达式CTE,这对于分层数据非常有用。触发器中也可能存在CTE

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);
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)

为什么不利用级联删除,因为这似乎正是您正在做的事情?不能,因为有多个级联路径:所以这是一个自连接表?是的,在某种程度上。ParentId引用同一个表中的Id非常感谢您的回答。我尝试了一些CTE的东西,并写了自己的答案。非常感谢您的意见/建议。谢谢Alex,我想从其他人那里知道tb不在这里,因为ParentId和Id来自同一张表。顺便说一句,我添加了一个关于CTE实施的答案。一定要让我知道您对此的看法。您是说OP中的某些\u tb和其他\u tb是同一个表吗?这里的目标是删除某些\u tb的所有嵌套子级,包括与某些\u tb引用的其他\u tb的记录。问题中所描述的问题是,所有嵌套的子项都没有被删除。正如您在我的回答中看到的,它们现在被删除了。如果其他人有自己的层次结构,那么在锚查询中选择顶级id就足够了。对不起,我无法理解您的答案。不管怎样,我已经投了更高的票。没有必要在@deleted中table@AlexKudryashev那么如何插入CTE找到的新ID?已删除的联合?不需要插入它们。直接使用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)