【问题标题】:How To Traverse a Tree/Work With Hierarchical data in SQL Code如何在 SQL 代码中遍历树/使用分层数据
【发布时间】:2019-07-31 22:36:57
【问题描述】:

假设我有一个员工表,其中包含公司中每个员工的记录,以及主管列(如下所示)。我想准备一份报告,其中列出了监管行中每个步骤的名称和标题。例如,对于 dick robbins,1d #15,我想要一份他的“指挥链”中每个主管的名单,一直到总统,大奶酪。我想避免使用游标,但如果这是唯一的方法,那没关系。

id  fname   lname   title   supervisorid
1   big     cheese  president   1
2   jim     william vice president  1
3   sally   carr    vice president  1
4   ryan    allan   senior manager  2
5   mike    miller  manager 4
6   bill    bryan   manager 4
7   cathy   maddy   foreman 5
8   sean    johnson senior mechanic 7
9   andrew  koll    senior mechanic 7 
10  sarah   ryans   mechanic    8
11  dana    bond    mechanic    9
12  chris   mcall   technician  10
13  hannah  ryans   technician  10
14  matthew miller  technician  11
15  dick    robbins technician  11

真正的数据可能不会超过 10 层深...但我宁愿不只是做 10 次外部联接...我希望有比这更好的东西,而且比游标少涉及。

感谢您的帮助。

【问题讨论】:

标签: sql sql-server sql-server-2008


【解决方案1】:

这基本上是我在 OP cmets 中链接到的问题的已接受答案的一个端口。

您可以使用公用表表达式

WITH Family As 
( 
    SELECT e.id, e.supervisorid, 0 as Depth
    FROM Employee e
    WHERE id = @SupervisorID 
    UNION All 
    SELECT e2.ID, e2.supervisorid, Depth + 1
    FROM Employee e2
        JOIN Family 
            On Family.id = e2.supervisorid 
) 
SELECT*
FROM Family 

更多:

Recursive Queries Using Common Table Expressions

【讨论】:

  • @ 字符到底是什么意思?你必须提供一个参数吗?我不清楚,但我最终想要做的是提供所有员工的名单,以及他们各自的所有“指挥链”......对于每个员工,而不仅仅是一个员工。你能改变你的查询来执行这个吗?
  • @SupervisorID 是如果你想让一个“根”人加入一个链。如果您想要所有链,只需完全删除 where 子句行,它应该可以工作。
  • 我认为@SupervisorID是递归的关键。 CTE 中的第二个查询(递归成员)使用员工 ID 回调 Family。第一个查询(锚定成员)必须能够在每次递归时仅获取该给定员工 ID 下的员工。由于您第一次访问锚成员,您没有提供员工 ID,而是从顶层开始,即主管 ID 为空的员工。如果你没有那个@SupervisorID,你会破坏递归。
【解决方案2】:

您可能对“Materialized Path”解决方案感兴趣,该解决方案对表进行了轻微的反规范化,但可用于任何类型的 SQL 数据库,并避免您进行递归查询。事实上,它甚至可以用于非 SQL 数据库。

您只需要添加一个包含对象的整个祖先的列。例如,下表包含名为tree_path 的列:

+----+-----------+----------+----------+
| id | value     | parent   | tree_path|
+----+-----------+----------+----------+
|  1 | Some Text |        0 |          |
|  2 | Some Text |        0 |          |
|  3 | Some Text |        2 |       -2-|
|  4 | Some Text |        2 |       -2-|
|  5 | Some Text |        3 |     -2-3-|
|  6 | Some Text |        3 |     -2-3-|
|  7 | Some Text |        1 |       -1-|
+----+-----------+----------+----------+

选择 id=2 记录的所有后代如下所示:

SELECT * FROM comment_table WHERE tree_path LIKE '-2-%' ORDER BY tree_path ASC

要构建一棵树,您可以按tree_path 排序以获得一个相当容易转换为树的数组。

你也可以索引tree_path,当通配符不在开头时可以使用索引。

例如tree_path LIKE '-2-%'可以使用索引,但tree_path LIKE%-2-'`不能。

【讨论】:

    【解决方案3】:

    一些递归函数,它要么返回主管(如果有的话)要么返回 null。可能是一个 SP,它也调用自己,并使用 UNION。

    【讨论】:

      【解决方案4】:

      SQL 是一种用于执行 set 操作的语言,而递归不是其中之一。此外,许多数据库系统在递归方面存在限制,使用存储过程作为一种安全措施,以防止流氓代码占用宝贵的服务器资源。

      因此,在使用 SQL 时,请始终考虑 'flat',而不是“分层”。因此,我强烈推荐已建议的 'tree_path' 方法。我使用了同样的方法,它的效果非常好,非常关键,非常稳健

      【讨论】:

        猜你喜欢
        • 2014-07-19
        • 1970-01-01
        • 1970-01-01
        • 2013-09-12
        • 1970-01-01
        • 2013-09-25
        • 1970-01-01
        • 2021-12-23
        • 2013-08-24
        相关资源
        最近更新 更多