SQL 2005 - 公用表表达式 - 查找层次结构中的最后一个
假设我有下表:
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
的员工,我想找到链中的最后一个人,在本例中为“公司总裁 1 - 副总裁 - 秘书 - 三明治外卖
”和“公司总裁 2 - 副总裁 - 秘书
”。
我有以下 CTE,它为我提供了包括嵌套级别在内的所有内容,但我不确定从这里到哪里去。如果可能的话,我想避免使用光标。
另外,这非常重要,我在其他地方有逻辑保证一名员工只能有 1 名直接下属。因此,尽管架构在技术上允许,但公司总裁 1
永远不会列出两名副总裁。
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
Let's say I've got the following table:
CREATE TABLE Employees
(
EmployeeId int PRIMARY KEY NOT NULL,
ParentEmployeId int REFERENCES Employees(EmployeeId) NULL,
Name varChar(255)
)
All records have a primary identifier and records are able to identify another record as a parent. (My actual schema isn't about employees, this is just a simplified version for illustration so if you've got a better way of handling employee information its not germane to this conversation.)
The following records are inserted:
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')
These inserts represent:
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
What I'm trying to do is for all employees that have a NULL ParentEmployeeId
I want to find the last person in the chain, which in this example would be "Company President 1 - VP - Secretary - Sandwich Delivery
" and "Company President 2 - VP - Secretary
".
I've got the following CTE which gives me everything including the nesting level but I'm not sure where to go from here. I'd like to avoid cursors if possible.
Also, and this is very important, I have logic elsewhere that guarantees that an employee can only have 1 direct subordinate. So although the schema technically allows for it, Company President 1
will never have two VP's listed.
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这里的关键是跟踪递归 CTE 中的顶级父级:
... 形成一个中间 CTE 来捕获“自下而上”的级别 ...
... 对于每个最终的 grandboss ,选择它们最深的子级:(
将所有这些代码片段连接在一起,形成具有两个 CTE 和一个
SELECT
的单个查询)结果:
您可以将其
JOIN
返回到员工
获取最终大老板的姓名或跟踪 CTE 中的姓名,这在您的实际情况中是有意义的。The key here is to keep track of the top-level parent in the recursive CTE:
... form an intermediate CTE to capture the 'bottom up' level ...
... for each ultimate grandboss, select their deepest child:
(concatenate together all these code fragments to form a single query with two CTEs and a
SELECT
)Results:
You can
JOIN
this back toEmployee
to get ultiamte grandboss names or track the names in the CTE, as makes sense in your actual situation.跟踪您的主 EmployeeID 允许您将结果与最后一个级别连接起来,以保留您需要的记录。
Keeping track of your master EmployeeID allows you to join the results with the last level to retain the records you need.