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)
跟踪主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)