SQL 2005 - 公用表表达式 - 在层次结构中查找最后一个

Chr*_*aas 7 t-sql common-table-expression

假设我有下表:

CREATE TABLE Employees
(
EmployeeId int PRIMARY KEY NOT NULL,
ParentEmployeId int REFERENCES Employees(EmployeeId) NULL,
Name varChar(255)
)
Run Code Online (Sandbox Code Playgroud)

所有记录都有主要标识符,记录能够将另一条记录标识为父级.(我的实际架构不是关于员工,这只是一个简化的插图版本,所以如果你有一个更好的方式处理员工信息,它与这个对话没有密切关系.)

插入以下记录:

INSERT INTO Employees VALUES (1, NULL, 'Company President 1')
INSERT INTO Employees VALUES (2, NULL, 'Company President 2')

INSERT INTO Employees VALUES (3, 1, 'Company President 1 - VP')
INSERT INTO Employees VALUES (4, 2, 'Company President 2 - VP')

INSERT INTO Employees VALUES (5, 3, 'Company President 1 - VP - Secretary')
INSERT INTO Employees VALUES (6, 4, 'Company President 2 - VP - Secretary')

INSERT INTO Employees VALUES (7, 5, 'Company President 1 - VP - Secretary - Sandwich Delivery')
Run Code Online (Sandbox Code Playgroud)

这些插入代表:

Company President 1
    Company President 1 - VP
        Company President 1 - VP - Secretary
            Company President 1 - VP - Secretary - Sandwich Delivery
Company President 2
    Company President 2 - VP
        Company President 2 - VP - Secretary
Run Code Online (Sandbox Code Playgroud)

我想要做的是为所有拥有NULL的员工,ParentEmployeeId我想找到链中的最后一个人,在这个例子中将是" Company President 1 - VP - Secretary - Sandwich Delivery"和" Company President 2 - VP - Secretary".

我有以下CTE给了我一切,包括筑巢水平,但我不知道从哪里开始.如果可能的话我想避免使用游标.

此外,这非常重要,我在其他地方有逻辑,保证员工只能拥有1个直接下属.因此,虽然模式在技术上允许它,但Company President 1永远不会列出两个VP.

WITH EmployeeRec(EmployeeId, ParentEmployeeId, Name, Level) AS
(
    SELECT
        EmployeeId,
        ParentEmployeId,
        Name,
        1 as [Level]
    FROM
        Employees
    WHERE
        ParentEmployeId IS NULL

    UNION ALL

    SELECT
        E.EmployeeId,
        E.ParentEmployeId,
        E.Name,
        R.[Level] + 1
    FROM
        Employees E
    INNER JOIN
        EmployeeRec R
    ON
        E.ParentEmployeId = R.EmployeeId
)
SELECT * FROM EmployeeRec
Run Code Online (Sandbox Code Playgroud)

Lie*_*ers 6

跟踪主EmployeeID允许您将结果与最后一级结合以保留所需的记录.

WITH EmployeeRec(Master, EmployeeId, ParentEmployeeId, Name, Level) AS
(
    SELECT
        [Master] = EmployeeId,
        EmployeeId,
        ParentEmployeId,
        Name,
        1 as [Level]
    FROM
        Employees
    WHERE
        ParentEmployeId IS NULL

    UNION ALL

    SELECT
        R.Master,
        E.EmployeeId,
        E.ParentEmployeId,
        E.Name,
        R.[Level] + 1
    FROM
        Employees E
    INNER JOIN
        EmployeeRec R
    ON
        E.ParentEmployeId = R.EmployeeId
)
SELECT  *
FROM    EmployeeRec er
        INNER JOIN (
          SELECT  Master, Level = MAX(Level)
          FROM    EmployeeRec
          GROUP BY Master
        ) m ON m.Master = er.Master
               AND m.Level = er.Level
Run Code Online (Sandbox Code Playgroud)