SQL 2005 - Общее табличное выражение - Найти последнее в иерархии - PullRequest
7 голосов
/ 17 ноября 2010

Допустим, у меня есть следующая таблица:

CREATE TABLE Employees
(
EmployeeId int PRIMARY KEY NOT NULL,
ParentEmployeId int REFERENCES Employees(EmployeeId) NULL,
Name varChar(255)
)

Все записи имеют первичный идентификатор, и записи могут идентифицировать другую запись как родительскую. (Моя настоящая схема не относится к сотрудникам, это просто упрощенная версия для иллюстрации, поэтому, если у вас есть более удобный способ обработки информации о сотрудниках, это не имеет отношения к этому разговору.)

Вставлены следующие записи:

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')

Эти вставки представляют:

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

Я пытаюсь сделать это для всех сотрудников, имеющих 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

Ответы [ 2 ]

6 голосов
/ 17 ноября 2010

Отслеживание вашего основного EmployeeID позволяет объединять результаты с последним уровнем для сохранения необходимых записей.

3 голосов
/ 17 ноября 2010

Ключом здесь является отслеживание родительского элемента верхнего уровня в рекурсивном CTE :

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

    UNION ALL

    SELECT
        E.EmployeeId,
        E.ParentEmployeeId,
        R.UltimateGrandbossEmployeeId,
        E.Name,
        R.[Level] + 1
    FROM
        Employees E
    INNER JOIN
        EmployeeRec R
    ON
        E.ParentEmployeeId = R.EmployeeId
)

... формировании промежуточного CTE для захвата «снизу вверх»уровень ...

SELECT 
    UltimateGrandbossEmployeeId,
    Name,
    ROW_NUMBER() OVER (PARTITION BY UltimateGrandbossEmployeeId 
                       ORDER BY Level Desc ) BottomUp
 FROM EmployeeRec
)

... для каждого конечного дедушки выберите их самого глубокого потомка:

SELECT
    UltimateGrandbossEmployeeId, DeepestChildName
FROM
    Inter
WHERE
    BottomUp = 1

(объедините все эти фрагменты кода, чтобы сформировать один запрос с двумя CTEи SELECT)

Результаты:

1   Company President 1 - VP - Secretary - Sandwich Delivery
2   Company President 2 - VP - Secretary

Вы можете JOIN вернуться обратно к Employee, чтобы получить имена ультиамтовых боссов или отслеживать имена в CTE, что имеет смыслв вашей реальной ситуации.

...