员工层级

问题描述 投票:0回答:1

我正在尝试生成一个结果,该结果将为每个员工的每个管理级别显示一行。

我可以做一个递归 cte 来找出一个人所处的级别,但我想看到的是一个结果集,显示该人在其结构中的每个级别上重复的情况。

例如,5 级员工应显示 5 行,每行都会重复员工姓名,以及该行的经理和当前级别。

我使用 AdventureWorksDW2014 中的 [dbo].[DimEmployee] 表作为示例数据。

这是我想在结果集中看到的内容

enter image description here

这是显示级别的递归 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

enter image description here

sql sql-server
1个回答
0
投票

我能想到的有两种方法。您使用哪一个取决于用例。

仅解决一名员工

没有任何规定必须从根(即组织树中的 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 并不是最优的。如果您想“真正”执行此操作,我鼓励您将其具体化为表中的一列。此时您可以对其进行索引。当报告结构发生变化时,您确实会产生维护它的持有成本,但这是一个权衡。

© www.soinside.com 2019 - 2024. All rights reserved.