【问题标题】:Query to List all hierarchical children with parent, grandparent etc. from entire table查询以列出整个表中具有父级、祖父级等的所有分层子级
【发布时间】:2018-02-07 18:29:09
【问题描述】:

我有一个基本的 sql 表,其中有一个 ID 和一个可选的 parentID 来自同一个表。这有多个层次。我需要获取所有 ID 的列表,以及它的每个父级一直到顶部。

ID  | Name  | ParentID
_______________________
1     John    null
2     Doe     1
3     Mike    1
4     Neil    3
5     Sylvia  4
6     Mary    2

我需要这样的列表:

ID  | Parent | DirectParent
_______________________
2     1       1
3     1       1
4     3       1
4     1       0
5     4       1
5     3       0
5     1       0
  • 它会忽略任何没有父项的记录。
  • 对于每个孩子,都有一个与其父母之一匹配的记录
  • 有一个位列可以知道哪个父级是它的正上方

如何查询上表来获取这些数据?

【问题讨论】:

  • 请在您使用的 DBMS 中添加标签
  • 到目前为止你尝试了什么????

标签: sql sql-server recursive-query


【解决方案1】:

递归 CTE 将在这里完成这项工作。最棘手的部分是获取直接父位列,希望我从预期结果中正确理解了逻辑。作为奖励,我为所有可能的路径添加了一个实际的报告层次结构列。 (这里递归深度最多10倍)

    CREATE TABLE #MyTable
    (
    ID int primary key,
    Name nvarchar (max),
    ParentID int
    )

    INSERT INTO #MyTable
    Values (1, 'John', null),
    (2, 'Doe', 1),
    (3, 'Mike', 1),
    (4, 'Neil', 3),
    (5, 'Sylvia', 4),
    (6, 'Mary', 2)

    WITH FindRoot AS
    (
        SELECT ID, ParentId, ParentId as Parent, CAST(Name AS NVARCHAR(MAX)) Path, 0 Distance
        FROM #MyTable

        UNION ALL

        SELECT P.ID, p.ParentId, c.Parent, C.Path + N' > ' + CAST(Name AS NVARCHAR(MAX)), C.Distance + 1
        FROM #MyTable P
        JOIN FindRoot C
        ON C.ID  = P.ParentId AND P.ParentId <> P.ID and C.ParentId <> c.ID 
        WHERE C.DISTANCE < 10
     )
    SELECT R.ID, R.Parent,
    CASE WHEN R1.Parent IS NULL THEN 1
    ELSE 0
    END AS DirectParent,  R.Path as ReportingHierarchy
    FROM FindRoot R
    LEFT JOIN FindRoot R1 on R1.ID = R.ID and R1.Parent =
    (SELECT Top 1 Parent From FindRoot
    WHERE ID = R.ID and Parent > R.Parent 
    Order by Parent)
    WHERE  R.Distance >= 0 and R.ParentId is not null
    Order by R.ID, R.distance
    option(maxrecursion 10)

结果如下:

    +----+--------+--------------+----------------------+
    | ID | Parent | DirectParent |  ReportingHierarchy  |
    +----+--------+--------------+----------------------+
    |  2 |      1 |            1 | Doe                  |
    |  3 |      1 |            1 | Mike                 |
    |  4 |      3 |            1 | Neil                 |
    |  4 |      1 |            0 | Mike > Neil          |
    |  5 |      4 |            1 | Sylvia               |
    |  5 |      3 |            0 | Neil > Sylvia        |
    |  5 |      1 |            0 | Mike > Neil > Sylvia |
    |  6 |      2 |            1 | Mary                 |
    |  6 |      1 |            0 | Doe > Mary           |
    +----+--------+--------------+----------------------+

编辑: 可能应该提到这一点,但根据对此答案的评论 - 确保您的 ParentIDID 列已编入索引。

【讨论】:

  • 对这种方法的注意事项 - 确保索引是经过仔细构建和调整的,即使这样,它也往往比大多数查询运行得更慢,尤其是在深层树中。
  • @theMayer 当您说这会比大多数查询运行得慢时,您还想到了哪些其他查询?递归 CTE 是我能想到的用于完成 OP 正在寻找的最佳查询。
  • 一种更快的方式使用HierarchyId,但是,维护此列(至少在 SQL 2012 中,我从那以后就没有使用它)是一件痛苦的事情。最终,我完全抛弃了 SQL 服务器,转而使用 Couchbase 的方法,它的执行速度比使用 HierarchyId 的优化查询快 10 倍。顺便说一句,我们谈论的是数百万个相关的对象。
  • 澄清一下,当我说“大多数查询”时——我不是指大多数递归查询,我指的是一般的大多数查询(例如,从视图中选择、使用复杂的表值函数进行选择等) .)。对于编写良好的代码,我确实对您的答案投了赞成票。
猜你喜欢
  • 1970-01-01
  • 2013-08-20
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 2022-10-29
  • 1970-01-01
  • 2015-12-04
  • 2017-02-18
相关资源
最近更新 更多