我正在尝试生成一个结果,该结果将为每个员工的每个管理级别显示一行。
我可以做一个递归 cte 来找出一个人所处的级别,但我想看到的是一个结果集,显示该人在其结构中的每个级别上重复的情况。
例如,5 级员工应显示 5 行,每行都会重复员工姓名,以及该行的经理和当前级别。
我使用 AdventureWorksDW2014 中的 [dbo].[DimEmployee] 表作为示例数据。
这是我想在结果集中看到的内容
这是显示级别的递归 CTE,但是我可以使用什么其他查询来获取每个级别的多行,就像上面的示例一样。
WITH RCTE AS
(
SELECT
E.EmployeeKey,
E.FirstName + ' ' + E.LastName AS Name,
E.ParentEmployeeKey,
1 AS Level
FROM
[dbo].[DimEmployee] AS E
WHERE
E.ParentEmployeeKey IS NULL
UNION ALL
SELECT
E.EmployeeKey,
E.FirstName + ' ' + E.LastName AS Name,
E.ParentEmployeeKey,
RCTE.Level + 1 AS Level
FROM
[dbo].[DimEmployee] AS E
JOIN
RCTE ON E.ParentEmployeeKey = RCTE.EmployeeKey
)
SELECT
RCTE.*
FROM
RCTE
WHERE
RCTE.EmployeeKey = 265
ORDER BY
RCTE.Level, RCTE.ParentEmployeeKey, RCTE.EmployeeKey
我能想到的有两种方法。您使用哪一个取决于用例。
没有任何规定必须从根(即组织树中的 CEO)到叶(即组织树中的关联)遍历层次结构。如果您只想获取一名员工的报告结构,您可以从该员工开始,向根部移动。
WITH RCTE AS
(
SELECT
E.EmployeeKey,
E.FirstName + ' ' + E.LastName AS Name,
E.ParentEmployeeKey,
1 AS Level
FROM
[dbo].[DimEmployee] AS E
WHERE
E.EmployeeKey = 265
UNION ALL
SELECT
parent.EmployeeKey,
parent.FirstName + ' ' + parent.LastName AS Name,
parent.ParentEmployeeKey,
child.Level + 1 AS Level
FROM
[dbo].[DimEmployee] AS parent
JOIN
RCTE as child ON child.ParentEmployeeKey = parent.EmployeeKey
)
select *
from RCTE
order by level desc
注意 - 这些级别与根到叶遍历中的级别相反。如果你需要 CEO 为 1 级,而叶级员工为最高级别,你就必须做一些数学计算。
如果您想将多个员工传递给查询,它会变得有点棘手(但也不是很困难)。我将使用hierarchyid(它是特定于SQL Server 的,但是是具体化路径模式的一般实现)。这里的想法是,我们将回到根到叶的遍历,但同时建立到树中每个节点的路径。然后,我们可以使用给定员工的该路径作为返回根的方法。
WITH RCTE AS
(
SELECT
E.EmployeeKey,
E.FirstName + ' ' + E.LastName AS Name,
E.ParentEmployeeKey,
1 AS Level,
cast(concat('/', E.EmployeeKey, '/') as varchar(1000)) as h
FROM
[dbo].[DimEmployee] AS E
WHERE
E.ParentEmployeeKey IS NULL
UNION ALL
SELECT
E.EmployeeKey,
E.FirstName + ' ' + E.LastName AS Name,
E.ParentEmployeeKey,
RCTE.Level + 1 AS Level,
cast(concat(RCTE.h, e.EmployeeKey, '/') as varchar(1000))
FROM
[dbo].[DimEmployee] AS E
JOIN
RCTE ON E.ParentEmployeeKey = RCTE.EmployeeKey
)
SELECT
parent.*
FROM
RCTE as parent
JOIN
RCTE as child
ON
cast(child.h as hierarchyid).IsDescendantOf(cast(parent.h as hierarchyid)) = 1
WHERE
child.EmployeeKey = 265
ORDER BY
child.Level, child.ParentEmployeeKey, child.EmployeeKey;
现在,我要说的是,在每个查询上动态计算 hierarchyid 并不是最优的。如果您想“真正”执行此操作,我鼓励您将其具体化为表中的一列。此时您可以对其进行索引。当报告结构发生变化时,您确实会产生维护它的持有成本,但这是一个权衡。