【问题标题】:Sql Server 2014 - Deep Recursive Parent-Child Self JoinSql Server 2014 - 深度递归父子自加入
【发布时间】:2019-03-21 18:58:32
【问题描述】:

我正在尝试构建一个深度递归自联接查询。有这样的表:

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

对于 Id 1,我的查询应该获取 1、2、3、4、5,因为它们要么是 1 的孩子,要么是 1 的孩子的孩子。在给定的示例中,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

想法?

【问题讨论】:

  • 你的结果不会包括 6 和 7。你是什么意思得到吨重复?
  • ibb.co/TPxHXVj - 抱歉链接,不知道我该如何在评论中格式化它。谢谢。
  • 您是否需要能够从层次结构中的任意点开始并沿树向下遍历(例如,在本例中,您是否希望能够从 Id = 2 开始)?

标签: sql sql-server recursion recursive-query


【解决方案1】:

您可以尝试使用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

【讨论】:

  • 这个答案是正确的。我花了一些时间研究它并期望有 10 个节点,但与此同时,一个错误的运行脚本在我没有注意到的一个节点下插入了 1000 条新记录。问题中的原始查询给出了正确的输出,数据不正确。
【解决方案2】:

使用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

【讨论】:

    【解决方案3】:

    我没有看到重复。

    您的代码根据您提供的数据返回以下内容:

    Id  ParentId
    1   
    2   1
    3   1
    5   3
    4   2
    

    这就是你想要的。

    Here 是一个 dbfiddle。

    代码如下:

    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;
    

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

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

    然后运行递归逻辑。

    【讨论】:

      【解决方案4】:

      试试这个产生父子层次结构的 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\2
      3    1\3
      5    1\3\5
      4    1\2\4
      

      【讨论】:

        【解决方案5】:

        这个查询会帮助你

        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
        

        【讨论】:

          猜你喜欢
          • 2014-05-19
          • 2020-07-23
          • 2017-02-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多