通过CTE获得所有员工

时间:2015-04-10 11:05:16

标签: sql-server sql-server-2012 common-table-expression

我有一张包含员工详细信息的表

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

现在,我必须从员工身份2开始,发现所有人都是低级别的雇员(即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)

我怎样才能达到同样的目标?

2 个答案:

答案 0 :(得分:2)

你可以尝试这样的事情

;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

答案 1 :(得分:1)

了解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来实际建立层次结构,但是这个人的任何实际查询都会向这个人报告?"和#34;谁报告给这个人?"最终从#employees表中的持久化层次结构中得到满足。最后的两个查询显示了如何在任一方向上遍历层次结构。如果您的层次结构很大(宽,深或两者),这种事情很重要。您需要在组织结构图更改时进行维护,但这是一次性操作。查询数据应该很快,因为谱系与员工记录保持一致。

顺便提一下,您的Level列对我来说有点奇怪。具体而言,它似乎倒退(即CEO具有最高水平)。我之所以这么说是因为如果/当你在组织结构图中添加另一个级别时,你需要重新调整CEO的每个级别。如果您的首席执行官具有最低级别,那么您只需将该级别降至最低级别,并且不必重新调整任何级别。