如何在SQL代码中遍历树/使用分层数据
假设我有一个employee表,其中包含公司每位员工的记录,以及主管的一列(如下所示)。我想准备一份报告,其中列出了监督行中每个步骤的名称和标题。例如,对于15岁的迪克·罗宾斯(dick robbins),我想要一份他“指挥链”中每个主管的名单,一直到总统,大奶酪(big cheese)。我想避免使用游标,但如果这是唯一的方法,那也没关系如何在SQL代码中遍历树/使用分层数据,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,假设我有一个employee表,其中包含公司每位员工的记录,以及主管的一列(如下所示)。我想准备一份报告,其中列出了监督行中每个步骤的名称和标题。例如,对于15岁的迪克·罗宾斯(dick robbins),我想要一份他“指挥链”中每个主管的名单,一直到总统,大奶酪(big cheese)。我想避免使用游标,但如果这是唯一的方法,那也没关系 id fname lname title supervisorid 1 big cheese president 1 2
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个外部连接…我希望有比这更好的东西,并且比游标少参与
感谢您的帮助。这基本上是我在OP评论中链接到的关于我的问题的公认答案 可以使用公共表表达式
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
更多信息:
一些递归函数,它返回监管者(如果有)或null。也可以是一个调用自身并使用UNION的SP。您可能会对“物化路径”解决方案感兴趣,该解决方案会稍微对表进行非规范化,但可以用于任何类型的SQL数据库,并防止您进行递归查询。事实上,它甚至可以在没有SQL的数据库上使用 您只需要添加一个列来保存对象的整个祖先。例如,下表包括一个名为
tree\u 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\u path
进行排序,以获得非常容易转换为树的数组
您还可以索引树路径
,当通配符不在开头时,可以使用索引
例如,
tree\u path LIKE'-2-%'
可以使用索引,但是tree\u path LIKE
%-2-'`不能使用索引。SQL是执行set操作的语言,递归不是其中之一。此外,许多数据库系统在使用存储过程作为安全措施防止恶意代码带着宝贵的服务器资源逃逸时,对递归有限制
因此,在使用SQL时,请始终考虑“扁平化”,而不是“层次化”。因此,我强烈推荐所建议的'tree\u path'方法。我使用了相同的方法,它工作得非常出色,非常关键,非常有力您可能会对我的问题感兴趣:您的数据有一个小问题,记录id 1不能有supervisorid=1它会破坏CTE表@字符的确切用途是什么?您必须提供一个参数吗?我不清楚,但我最终想做的是提供一份所有员工的列表,以及他们各自的“指挥链”…针对每个员工,而不仅仅是一个。您可以更改查询以执行此操作吗?@SupervisorID是指您希望链中有一个“root”人员。如果您想要所有的链,只需删除where子句行就可以了。我认为@SupervisorID是递归的关键。CTE内的第二个查询(递归成员)调用带有员工id的Family。第一个查询(锚成员)必须能够在每次递归中仅获取在给定员工id下的员工。由于第一次访问锚定成员时,您没有提供员工id,因此从顶层开始,即员工的主管id为空。如果您没有@SupervisorID,则会中断递归。