通过 CTE 让所有员工都在经理之下

Get all employees under manager with CTE

我有一个 table,其中包含员工详细信息

EmpId ManagerId Level Value
1      0         5     CEO
2      1         4     EMP
3      1         4     ORG
4      2         3     NULL
5      2         3     NULL
6      2         2     NULL
7      1         1     NULL
8      5         0     NULL

现在,我必须从 Employee Id 2 开始,找到它的所有低级别 hirerachy(即 2、4、5、6、8)并为它们分配与“2”相同的值(即 EMP)。

预期输出:

  EmpId ManagerId Level Value
    1      0         5     CEO
    2      1         4     EMP
    3      1         4     ORG
    4      2         3     EMP
    5      2         3     EMP
    6      2         2     EMP
    7      1         1     NULL
    8      5         0     EMP

我在尝试什么:

    ; WITH LevelHire AS
(
        SELECT EmpId, ManagerId,Level
        FROM EmployeeTable
        WHERE EmpId =2
        UNION ALL
        SELECT Lh.EmpId,  RC.ManagerId, Lh.Level
        FROM LevelHire LH
        INNER JOIN [EmployeeTable] RC
        ON LH.EmpId= RC.EmpId

)

SELECT * FROM LevelHire
option (maxrecursion 0)

我怎样才能达到同样的效果?

你可以试试这个

;WITH EmployeeTable AS 
(
SELECT 1 EmpId,0 ManagerId ,   5 Level ,'CEO' Value
UNION ALL SELECT 2,1,   4,'EMP'
UNION ALL SELECT 3,1,   4,'ORG'
UNION ALL SELECT 4,2,   3,NULL
UNION ALL SELECT 5,2,   3,NULL
UNION ALL SELECT 6,2,   2,NULL
UNION ALL SELECT 7,1,   1,NULL
UNION ALL SELECT 8,5,   0,NULL
),LevelHire AS
(
        SELECT EmpId, ManagerId,Level,Value
        FROM EmployeeTable
        WHERE EmpId = 2
        UNION ALL
        SELECT RC.EmpId,  RC.ManagerId, Lh.Level,LH.Value
        FROM LevelHire LH
        INNER JOIN [EmployeeTable] RC
        ON LH.EmpId= RC.ManagerId
)
SELECT  E.EmpId, E.ManagerId,E.Level,ISNULL(E.Value ,LH.Value) Value
FROM EmployeeTable E
    LEFT JOIN LevelHire LH
    ON E.EmpId = LH.EmpId

是时候了解 hierarchyid 了。首先,一些代码:

IF object_id('tempdb.dbo.#employees') IS NOT NULL
    DROP TABLE #employees;
go
WITH Employees AS (
    SELECT  *
    FROM    ( VALUES 
        ( 1, NULL, 5, 'CEO'), 
        ( 2, 1, 4, 'EMP'), 
        ( 3, 1, 4, 'ORG'),
        ( 4, 2, 3, NULL ), 
        ( 5, 2, 3, NULL ), 
        ( 6, 2, 2, NULL ),
        ( 7, 1, 1, NULL ), 
        ( 8, 5, 0, NULL ) 
    ) AS x ( EmpId, ManagerId, Level, Value ) 
), rcte AS (
    SELECT e.EmpId ,
           e.ManagerId ,
           e.Level ,
           e.Value,
           CAST('/' + CAST(e.EmpId AS VARCHAR) + '/' AS VARCHAR(MAX)) AS h
    FROM Employees AS e
    WHERE e.ManagerId IS NULL

    UNION ALL

    SELECT e.EmpId ,
           e.ManagerId ,
           e.Level ,
           e.Value ,
           m.h + CAST(e.EmpId AS VARCHAR) + '/' AS h
    FROM Employees AS e
    JOIN rcte AS m
        ON e.ManagerId = m.EmpId
)
SELECT rcte.EmpId ,
       rcte.ManagerId ,
       rcte.Level ,
       rcte.Value ,
       CAST(rcte.h AS HIERARCHYID) AS h
INTO #employees
FROM rcte;
GO

SELECT  e.EmpId ,
        e.ManagerId ,
        e.Level ,
        e.Value ,
        e.h.ToString() AS h
FROM    #employees AS e
JOIN    #employees AS m
        ON e.h.IsDescendantOf(m.h) = 1
WHERE   m.EmpId = 1

SELECT  m.EmpId ,
        m.ManagerId ,
        m.Level ,
        m.Value ,
        m.h.ToString() AS h
FROM    #employees AS e
JOIN    #employees AS m
        ON e.h.IsDescendantOf(m.h) = 1
WHERE   e.EmpId = 8

虽然我需要一个递归 CTE 来实际建立层次结构,但任何形式为 "who does this person report to?" 和 "who reports to this person?" 的实际查询最终都会从 #employees [=21] 中的持久层次结构中得到满足=].最后的两个查询显示了如何在任一方向上遍历层次结构。如果您的层次结构很大(宽、深或两者兼而有之),这种事情很重要。当组织结构图发生变化时,您确实需要维护它,但这是一次性操作。数据查询应该很快,因为沿袭与员工记录保持一致。

顺便说一下,您的 Level 专栏对我来说有点奇怪。具体来说,似乎倒退(即CEO级别最高)。我这样说是因为 if/when 你在组织结构图中增加了另一个级别,你需要重新分级从 CEO 到每个人。如果您的 CEO 级别最低,您只需将该级别添加到底部,而不必重新级别。