Sql Server 2014 - 深度递归 Parent-Child 自连接

Sql Server 2014 - Deep Recursive Parent-Child Self Join

我正在尝试构建深度递归 self-join 查询。让 table 像:

Id | ParentId
1  | NULL
2  | 1
3  | 1
4  | 2
5  | 3
6  | 8
7  | 9

对于 Id 1,我的查询应该获取 1,2,3,4,5,因为它们要么是 1 的 children,要么是 1 的 children 的 children。在给定的示例中,查询结果中不应包含 6 和 7。

我尝试使用 CTE,但我收到大量重复项:

WITH CTE AS (
    SELECT Id, ParentId
    FROM dbo.Table
    WHERE ParentId IS NULL
UNION ALL
    SELECT t.Id, t.ParentId
    FROM dbo.Table t
    INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT * FROM CTE

想法?

使用 CTE 尝试以下查询,您可以通过 @parentID 设置 parentId:

DECLARE @parentID INT = 1
;WITH cte AS 
(
    SELECT 
    t.ID
    , t.ParentId
    FROM @table t
),
cteParent AS
(
    SELECT 
    t.ID
    , t.ParentId
    FROM @table t
    WHERE t.ParentId IN (SELECT t1.ID FROM @table t1 WHERE T1.ParentId = @parentID)
)

SELECT 
DISTINCT c1.ID
, c1.ParentId
FROM cte c1
INNER JOIN cte c2 ON c2.ParentId = c1.ID
UNION ALL 
SELECT * 
FROM cteParent

样本数据:

DECLARE @table TABLE
(
    ID INT
    , ParentId INT
)

INSERT INTO @table
(
    ID,
    ParentId
)
VALUES
  (1, NULL )
, (2, 1 )

, (3, 1 )

, (4, 2 )

, (5, 3 )

, (6, 8 )

, (7, 9 )

输出:

ID  ParentId
1   NULL
2   1
3   1
4   2
5   3

您可以尝试使用DISTINCT过滤重复的行。

;WITH CTE AS (
    SELECT Id, ParentId
    FROM T
    WHERE ParentId IS NULL
UNION ALL
    SELECT t.Id, t.ParentId
    FROM T
    INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT DISTINCT Id, ParentId
FROM CTE

试试这个 sql 脚本,结果是父子层次结构

;WITH CTE(Id , ParentId)
AS
(
SELECT 1 , NULL  UNION ALL
SELECT 2 , 1     UNION ALL
SELECT 3 , 1     UNION ALL
SELECT 4 , 2     UNION ALL
SELECT 5 , 3     UNION ALL
SELECT 6 , 8     UNION ALL
SELECT 7 , 9
)
,Cte2
AS
(
    SELECT Id , 
          ParentId ,
         CAST('\'+ CAST(Id AS VARCHAR(MAX))AS VARCHAR(MAX)) AS [Hierarchy]
    FROM CTE
    WHERE ParentId IS NULL
    UNION ALL
    SELECT c1.Id , 
          c1.ParentId ,
        [Hierarchy]+'\'+ CAST(c1.Id AS VARCHAR(MAX)) AS [Hierarchy]
    FROM Cte2 c2
    INNER JOIN CTE c1
    ON  c1.ParentId = c2.Id
)
SELECT Id,
       RIGHT([Hierarchy],LEN([Hierarchy])-1) AS ParentChildHierarchy 
FROM Cte2

GO

结果

Id  ParentChildHierarchy
-------------------------
1    1
2    1
3    1
5    1
4    1

我没有看到重复项。

您的代码returns您提供的数据如下:

Id  ParentId
1   
2   1
3   1
5   3
4   2

这就是你想要的。

Here 是一个 db<>fiddle.

代码如下:

WITH t as (
      SELECT *
      FROM (VALUES (1, NULL), (2, 1), (3, 1), (4, 2), (5, 3), (6, 8), (7, 9)
           ) v(id, parentId)
    ),
    CTE AS (
    SELECT Id, ParentId
    FROM t
    WHERE ParentId IS NULL
UNION ALL
    SELECT t.Id, t.ParentId
    FROM t
    INNER JOIN CTE c ON t.ParentId = c.Id
)
SELECT *
FROM CTE;

如果您在实际结果集中得到重复项,那么您可能在原始结果集中有重复项 table。我建议在 执行递归逻辑之前 删除它们:

with t as (
      select distinct id, parentid
      from <your query>
     ),
     . . .

然后运行递归逻辑。

这个查询会对你有帮助

CREATE TABLE #table( ID INT, ParentId INT )

INSERT INTO #table(ID,ParentId)
VALUES (1, NULL ), (2, 1 ), (3, 1 ), (4, 2 ), (5, 3 ), (6, 8 ), (7, 9 )

;WITH CTE AS (
SELECT ID FROM #table WHERE PARENTID IS NULL
UNION ALL
SELECT T.ID FROM #table T  
INNER JOIN  #table T1 ON T.PARENTID =T1.ID 
) SELECT * FROM CTE