递归CTE如何在SQL Server中工作?
有人能帮我理解这个递归CTE是如何工作的吗递归CTE如何在SQL Server中工作?,sql,sql-server,recursion,common-table-expression,Sql,Sql Server,Recursion,Common Table Expression,有人能帮我理解这个递归CTE是如何工作的吗 WITH RECURSIVECTE (EMPID, FULLNAME, MANAGERID, [ORGLEVEL]) AS (SELECT EMPID, FULLNAME, MANAGERID, 1 FROM RECURSIVETBL WHERE MANAGERID IS NULL UNION ALL SELECT A.EMPID,
WITH
RECURSIVECTE (EMPID, FULLNAME, MANAGERID, [ORGLEVEL]) AS
(SELECT EMPID,
FULLNAME,
MANAGERID,
1
FROM RECURSIVETBL
WHERE MANAGERID IS NULL
UNION ALL
SELECT A.EMPID,
A.FULLNAME,
A.MANAGERID,
B.[ORGLEVEL] + 1
FROM RECURSIVETBL A
JOIN RECURSIVECTE B ON A.MANAGERID = B.EMPID)
SELECT *
FROM RECURSIVECTE;
SQL Server中的递归CTE有两部分: 锚定:是递归的起点。这个集合将通过递归连接进一步扩展
SELECT
EMPID,
FULLNAME,
MANAGERID,
1 AS ORGLEVEL
FROM
RECURSIVETBL
WHERE
MANAGERID IS NULL
它似乎吸引了所有没有任何经理的员工(可能是顶级老板,或者是树形关系的根源)
递归:与联合所有
链接,此集合必须引用声明的CTE(从而使其递归)。想象一下,你将如何在下一个层次上扩展锚定的结果
UNION ALL
SELECT
A.EMPID,
A.FULLNAME,
A.MANAGERID,
B.[ORGLEVEL] + 1
FROM
RECURSIVETBL A
JOIN RECURSIVECTE B -- Notice that we are referencing "RECURSIVECTE" which is the CTE we are declaring
ON A.MANAGERID = B.EMPID
在本例中,我们正在获取(在第一次迭代中)锚定结果集(所有员工都没有经理),并通过MANAGERID
将其与RECURSIVETBL
连接,因此a.EMPID
将保留先前选择的经理的员工。只要最后的每个结果集都能生成新行,这种连接就会继续下去
对递归部分的设置有一些限制(例如,没有分组或其他嵌套递归)。此外,由于它前面有一个UNION ALL
,所以它的规则也适用(列的数量和数据类型必须匹配)
关于组织级别,它从设置为1的锚点开始(在那里硬编码)。当它在递归集上进一步展开时,它获取上一个集(第一次迭代时的锚点)并添加1,因为它的表达式是B.[ORGLEVEL]+1
,其中B
是上一个集。这意味着它以1(最高层)开始,并不断为每个子代添加1,从而代表组织的所有级别
当你发现一名员工在ORGLEVEL=3
时,意味着他有两名经理在管理他
一步一步地以工作为例 让我们按照这个例子:
EmployeeID ManagerID
1 NULL
2 1
3 1
4 2
5 2
6 1
7 6
8 6
9 NULL
10 3
11 3
12 10
13 9
14 9
15 13
ManagerID为空
)。这将从你公司的所有头号坏蛋开始。需要注意的是,如果锚定集为空,那么整个递归CTE将为空,因为没有起点,也没有要连接的递归集
SELECT
EmployeeID = E.EmployeeID,
ManagerID = NULL, -- Always null by WHERE filter
HierarchyLevel = 1,
HierarchyRoute = CONVERT(VARCHAR(MAX), E.EmployeeID)
FROM
Employee AS E
WHERE
E.ManagerID IS NULL
EmployeeID ManagerID HierarchyLevel HierarchyRoute
1 (null) 1 1
9 (null) 1 9
UNION ALL
递归:
UNION ALL
SELECT
EmployeeID = E.EmployeeID,
ManagerID = E.ManagerID,
HierarchyLevel = R.HierarchyLevel + 1,
HierarchyRoute = R.HierarchyRoute + ' -> ' + CONVERT(VARCHAR(10), E.EmployeeID)
FROM
RecursiveCTE AS R
INNER JOIN Employee AS E ON R.EmployeeID = E.ManagerID
内部联接
,递归CTE
有两行(锚定集),员工ID分别为1
和9
。所以这个JOIN
实际上会返回这个结果
HierarchyLevel EmployeeID ManagerID HierarchyRoute
2 2 1 1 -> 2
2 3 1 1 -> 3
2 6 1 1 -> 6
2 13 9 9 -> 13
2 14 9 9 -> 14
查看HierarchyRoute
如何从1和9开始并移动到每个后代?我们还将HierarchyLevel
增加了1
由于结果是通过一个联合ALL
链接的,因此此时我们得到以下结果(步骤1+2):
这里是棘手的部分,对于下面的每个迭代,对RecursiveCTE
的递归引用将只包含最后一个迭代结果集,而不包含累积集。这意味着在下一次迭代中,RecursiveCTE
将表示以下行:
HierarchyLevel EmployeeID ManagerID HierarchyRoute
2 2 1 1 -> 2
2 3 1 1 -> 3
2 6 1 1 -> 6
2 13 9 9 -> 13
2 14 9 9 -> 14
UNION ALL
SELECT
EmployeeID = E.EmployeeID,
ManagerID = E.ManagerID,
HierarchyLevel = R.HierarchyLevel + 1,
HierarchyRoute = R.HierarchyRoute + ' -> ' + CONVERT(VARCHAR(10), E.EmployeeID)
FROM
RecursiveCTE AS R
INNER JOIN Employee AS E ON R.EmployeeID = E.ManagerID
RecursiveCTE
,并将其添加到累计总计中,即:
HierarchyLevel EmployeeID ManagerID HierarchyRoute
1 1 (null) 1
1 9 (null) 9
2 2 1 1 -> 2
2 3 1 1 -> 3
2 6 1 1 -> 6
2 13 9 9 -> 13
2 14 9 9 -> 14
3 4 2 1 -> 2 -> 4
3 5 2 1 -> 2 -> 5
3 7 6 1 -> 6 -> 7
3 8 6 1 -> 6 -> 8
3 10 3 1 -> 3 -> 10
3 11 3 1 -> 3 -> 11
3 15 13 9 -> 13 -> 15
HierarchyLevel EmployeeID ManagerID HierarchyRoute
4 12 10 1 -> 3 -> 10 -> 12
HierarchyLevel EmployeeID ManagerID HierarchyRoute
1 1 (null) 1
1 9 (null) 9
2 2 1 1 -> 2
2 3 1 1 -> 3
2 6 1 1 -> 6
2 13 9 9 -> 13
2 14 9 9 -> 14
3 4 2 1 -> 2 -> 4
3 5 2 1 -> 2 -> 5
3 7 6 1 -> 6 -> 7
3 8 6 1 -> 6 -> 8
3 10 3 1 -> 3 -> 10
3 11 3 1 -> 3 -> 11
3 15 13 9 -> 13 -> 15
4 12 10 1 -> 3 -> 10 -> 12
以下是完整的代码:
CREATE TABLE Employee (EmployeeID INT, ManagerID INT)
INSERT INTO Employee (EmployeeID, ManagerID)
VALUES
(1, NULL),
(2, 1),
(3, 1),
(4, 2),
(5, 2),
(6, 1),
(7, 6),
(8, 6),
(9, NULL),
(10, 3),
(11, 3),
(12, 10),
(13, 9),
(14, 9),
(15, 13)
WITH RecursiveCTE AS
(
SELECT
EmployeeID = E.EmployeeID,
ManagerID = NULL, -- Always null by WHERE filter
HierarchyLevel = 1,
HierarchyRoute = CONVERT(VARCHAR(MAX), E.EmployeeID)
FROM
Employee AS E
WHERE
E.ManagerID IS NULL
UNION ALL
SELECT
EmployeeID = E.EmployeeID,
ManagerID = E.ManagerID,
HierarchyLevel = R.HierarchyLevel + 1,
HierarchyRoute = R.HierarchyRoute + ' -> ' + CONVERT(VARCHAR(10), E.EmployeeID)
FROM
RecursiveCTE AS R
INNER JOIN Employee AS E ON R.EmployeeID = E.ManagerID
)
SELECT
R.HierarchyLevel,
R.EmployeeID,
R.ManagerID,
R.HierarchyRoute
FROM
RecursiveCTE AS R
ORDER BY
R.HierarchyLevel,
R.EmployeeID
如果您的高层人数超过,则[ORGLEVEL]将始终从1开始
没有过帐数据无法提供详细信息。您能在这里更具体一点吗?特别是,你想解释什么?你问过写rCTE的人吗?首先,我想知道“B.[ORGLEVEL]+1”部分,我想知道它是如何迭代的,以及它是如何定义组织级别的。我知道你想解释什么,但我想知道“B.[ORGLEVEL]+1”这一部分。我不知道它是如何定义组织级别以及如何迭代的。为什么它不在第二个员工之后迭代?@VijayThapa我在末尾添加了一条关于组织级别的评论。但是它如何区分级别?我需要它explained@VijayThapa我添加了一个分步指南,让我知道还有一些豆豆谢谢你的完整指导:)对不起,我来晚了。
HierarchyLevel EmployeeID ManagerID HierarchyRoute
1 1 (null) 1
1 9 (null) 9
2 2 1 1 -> 2
2 3 1 1 -> 3
2 6 1 1 -> 6
2 13 9 9 -> 13
2 14 9 9 -> 14
3 4 2 1 -> 2 -> 4
3 5 2 1 -> 2 -> 5
3 7 6 1 -> 6 -> 7
3 8 6 1 -> 6 -> 8
3 10 3 1 -> 3 -> 10
3 11 3 1 -> 3 -> 11
3 15 13 9 -> 13 -> 15
4 12 10 1 -> 3 -> 10 -> 12
CREATE TABLE Employee (EmployeeID INT, ManagerID INT)
INSERT INTO Employee (EmployeeID, ManagerID)
VALUES
(1, NULL),
(2, 1),
(3, 1),
(4, 2),
(5, 2),
(6, 1),
(7, 6),
(8, 6),
(9, NULL),
(10, 3),
(11, 3),
(12, 10),
(13, 9),
(14, 9),
(15, 13)
WITH RecursiveCTE AS
(
SELECT
EmployeeID = E.EmployeeID,
ManagerID = NULL, -- Always null by WHERE filter
HierarchyLevel = 1,
HierarchyRoute = CONVERT(VARCHAR(MAX), E.EmployeeID)
FROM
Employee AS E
WHERE
E.ManagerID IS NULL
UNION ALL
SELECT
EmployeeID = E.EmployeeID,
ManagerID = E.ManagerID,
HierarchyLevel = R.HierarchyLevel + 1,
HierarchyRoute = R.HierarchyRoute + ' -> ' + CONVERT(VARCHAR(10), E.EmployeeID)
FROM
RecursiveCTE AS R
INNER JOIN Employee AS E ON R.EmployeeID = E.ManagerID
)
SELECT
R.HierarchyLevel,
R.EmployeeID,
R.ManagerID,
R.HierarchyRoute
FROM
RecursiveCTE AS R
ORDER BY
R.HierarchyLevel,
R.EmployeeID