我使用的是 SQL Server 2008 R2 SP1。 我想通过“沿着树向上走”来递归地找到某个组织单位的第一个非空经理。
我有一张包含组织单位“ORG”的表,一张包含每个组织的父级的表。 “ORG”中的单位,我们将该表命名为“ORG_PARENTS”,而包含每个组织单位的经理的一个表,我们将该表命名为“ORG_MANAGERS”。
ORG 有一个列 ORG_ID:
ORG_ID
1
2
3
ORG_PARENTS 有两列。
ORG_ID, ORG_PARENT
1, NULL
2, 1
3, 2
MANAGERS 有两列。
ORG_ID, MANAGER
1, John Doe
2, Jane Doe
3, NULL
我正在尝试创建一个递归查询,以查找特定组织部门的第一个非空经理。
基本上,如果我今天向经理查询 ORG_ID=3,我将得到 NULL。
SELECT MANAGER FROM ORG_MANAGERS WHERE ORG_ID = '3'
我希望查询使用 ORG_PARENTS 表来获取 ORG_ID=3 的父表,在本例中获取“2”,并对 ORG_ID=2 的 ORG_MANAGERS 表重复查询,并在此示例中返回“Jane Doe”。
如果查询也返回 NULL,我想对 ORG_ID=2 的父级重复该过程,即 ORG_ID=1 等。
到目前为止,我的 CTE 尝试都失败了,一个例子是:
WITH BOSS (MANAGER, ORG_ID, ORG_PARENT)
AS
( SELECT m.MANAGER, m.ORG_ID, p.ORG_PARENT
FROM dbo.MANAGERS m INNER JOIN
dbo.ORG_PARENTS p ON p.ORG_ID = m.ORG_ID
UNION ALL
SELECT m1.MANAGER, m1.ORG_ID, b.ORG_PARENT
FROM BOSS b
INNER JOIN dbo.MANAGERS m1 ON m1.ORG_ID = b.ORG_PARENT
)
SELECT * FROM BOSS WHERE ORG_ID = 3
它返回:
Msg 530, Level 16, State 1, Line 4 The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
MANAGER ORG_ID ORG_PARENT
NULL 3 2
最佳答案
您需要跟踪您开始时使用的原始 ID。试试这个:
DECLARE @ORG_PARENTS TABLE (ORG_ID INT, ORG_PARENT INT )
DECLARE @MANAGERS TABLE (ORG_ID INT, MANAGER VARCHAR(100))
INSERT @ORG_PARENTS (ORG_ID, ORG_PARENT)
VALUES (1, NULL)
, (2, 1)
, (3, 2)
INSERT @MANAGERS (ORG_ID, MANAGER)
VALUES (1, 'John Doe')
, (2, 'Jane Doe')
, (3, NULL)
;
WITH BOSS
AS
(
SELECT m.MANAGER, m.ORG_ID AS ORI, m.ORG_ID, p.ORG_PARENT, 1 cnt
FROM @MANAGERS m
INNER JOIN @ORG_PARENTS p
ON p.ORG_ID = m.ORG_ID
UNION ALL
SELECT m1.MANAGER, b.ORI, m1.ORG_ID, OP.ORG_PARENT, cnt +1
FROM BOSS b
INNER JOIN @ORG_PARENTS AS OP
ON OP.ORG_ID = b.ORG_PARENT
INNER JOIN @MANAGERS m1
ON m1.ORG_ID = OP.ORG_ID
)
SELECT *
FROM BOSS
WHERE ORI = 3
结果:
+----------+-----+--------+------------+-----+
| MANAGER | ORI | ORG_ID | ORG_PARENT | cnt |
+----------+-----+--------+------------+-----+
| NULL | 3 | 3 | 2 | 1 |
| Jane Doe | 3 | 2 | 1 | 2 |
| John Doe | 3 | 1 | NULL | 3 |
+----------+-----+--------+------------+-----+
一般提示:
不要预定义 CTE 的列;这是没有必要的,并且使维护变得烦人。
使用递归 CTE,始终保留一个计数器,这样您就可以限制递归性,并且可以跟踪您的深度。
编辑:
顺便说一句,如果你想要第一个非空管理器,你可以这样做(有很多方法):
SELECT BOSS.*
FROM BOSS
INNER JOIN (
SELECT BOSS.ORI
, MIN(BOSS.cnt) cnt
FROM BOSS
WHERE BOSS.MANAGER IS NOT NULL
GROUP BY BOSS.ORI
) X
ON X.ORI = BOSS.ORI
AND X.cnt = BOSS.cnt
WHERE BOSS.ORI IN (3)
关于sql - 具有三个表的递归 CTE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48769300/