不使用游标删除 SQL 表中的树节点

Dav*_*yan 1 t-sql sql-server

我有一个存储在 SQL 表中的字符串树,这是该表的定义。

CREATE TABLE [FileTree] (
    [ID]       INT           NOT NULL,
    [Name]     VARCHAR (MAX) NOT NULL,
    [ParentID] INT           NULL,
    [UserID]   VARCHAR (MAX) NOT NULL
);
Run Code Online (Sandbox Code Playgroud)

我有一个递归删除过程,用于删除节点及其子节点,它使用游标,并且在我上一个关于此事的问题中的用户指出语法问题后,它工作得非常好。(删除 SQL 表中的树节点

CREATE PROCEDURE DeleteFile 
    @FileID INTEGER,
    @UserID VARCHAR(MAX) 
AS
BEGIN
    DELETE FROM [FileTree] WHERE [ID] = @FileID AND [UserID]=@UserID;
    IF EXISTS(SELECT * FROM [FileTree] WHERE [ParentID] = @FileID AND [UserID]=@UserID)
    BEGIN
       DECLARE FileCursor CURSOR LOCAL FOR 
            SELECT [ID],[UserID] FROM [FileTree] WHERE [ParentID] = @FileID AND [UserID]=@UserID;
       OPEN FileCursor 
       FETCH NEXT FROM FileCursor INTO @FileID , @UserID 
       WHILE @@FETCH_STATUS =0
       BEGIN
            EXEC DeleteFile @FileID,@UserID;
            FETCH NEXT FROM FileCursor INTO @FileID , @UserID ;
       END
    END
  END
Run Code Online (Sandbox Code Playgroud)

然而,对问题的另一个答复建议使用通用表表达式,我用谷歌搜索,我认为我并不真正理解 CTE 如何替换此过程中的光标。有什么建议 ?

小智 5

您可以使用递归 CTE 获取应删除的 ID 的所有子级,然后在 DELETE 语句中使用它:

with all_ids as (
  select id, ParentID
  from FileTree
  where id = 4  -- this is the root ID that should be deleted

  union all

  select c.id, c.ParentID
  from FileTree c
    join all_ids p on p.id = c.ParentID
)
delete from file_tree
where id in (select id from all_ids);
Run Code Online (Sandbox Code Playgroud)

SQLFiddle 示例:http://sqlfiddle.com/#!3/ef474f /1