Recursive CTE with three tables的后续问题帮助我了解了SQL Server中的CTE。
最初的问题有什么变化?表MANAGERS
不再包含没有经理的org.units行。
目标是获得组织单位的第一个非空管理员。我已经使用COALESCE和OUTER JOIN了解它,我的问题是,是否可以使用递归查询?
示例代码如下。
DECLARE @ORG_PARENTS TABLE (ORG_ID INT, ORG_PARENT INT )
DECLARE @MANAGERS TABLE (ORG_ID INT, MANAGER VARCHAR(100))
DECLARE @ORG TABLE (ORG_ID INT, ORG_NAME VARCHAR(100))
INSERT @ORG (ORG_ID, ORG_NAME)
VALUES (1, 'One')
, (2, 'Two')
, (3, 'Three')
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')
;
-- The original answer
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
-- The following query only returns ORG "One" and "Two"
SELECT ORG.ORG_ID as "ORGID", ORG.ORG_NAME AS "NAME", MGR.MANAGER AS "MANAGER"
FROM @ORG ORG INNER JOIN @MANAGERS MGR ON MGR.ORG_ID = ORG.ORG_ID
-- The following query returns three rows, with NULL as the MANAGER for "Three"
-- My goal is to get the manager from the first parent that is not null
SELECT ORG.ORG_ID as "ORGID", ORG.ORG_NAME AS "NAME", (SELECT MANAGER FROM @MANAGERS M WHERE M.ORG_ID = ORG.ORG_ID) AS "MANAGER"
FROM @ORG ORG
-- The following workaround works, I can use COALESCE and a large number of OUTER JOINs to get the desired effect.
-- Is it possible to replace the code below with a recursive query, optimally where the number of levels is not hardcoded?
SELECT ORG.ORG_ID as "ORGID", ORG.ORG_NAME AS "NAME",
COALESCE(
(SELECT MANAGER FROM @MANAGERS M WHERE M.ORG_ID = ORG.ORG_ID),
(SELECT MANAGER FROM @MANAGERS M WHERE M.ORG_ID = p1.ORG_PARENT),
(SELECT MANAGER FROM @MANAGERS M WHERE M.ORG_ID = p2.ORG_PARENT)
) AS "MANAGER"
FROM @ORG ORG
LEFT OUTER JOIN @ORG_PARENTS p1 ON ORG.ORG_ID = p1.ORG_ID
LEFT OUTER JOIN @ORG o1 ON p1.ORG_PARENT = o1.ORG_ID
LEFT OUTER JOIN @ORG_PARENTS p2 ON o1.ORG_ID = p2.ORG_ID
LEFT OUTER JOIN @ORG o2 ON p2.ORG_PARENT = o2.ORG_ID
预期结果
我希望3的MANAGER列显示" Jane Doe"。例如,COALSECE(上面的最后一个SELECT)就是这样做的:
ORGID NAME MANAGER
1 One John Doe
2 Two Jane Doe
3 Three Jane Doe
答案 0 :(得分:1)
@ZLK在他/她的评论中是正确的,你不需要MANAGERS表来执行递归:
WITH BOSS
AS
(
SELECT P.ORG_ID AS ORI, P.ORG_ID, p.ORG_PARENT, 1 cnt
FROM @ORG_PARENTS p
UNION ALL
SELECT b.ORI, OP.ORG_ID, OP.ORG_PARENT, cnt +1
FROM BOSS b
INNER JOIN @ORG_PARENTS AS OP
ON OP.ORG_ID = b.ORG_PARENT
)
SELECT *
FROM BOSS
LEFT JOIN @MANAGERS m1
ON m1.ORG_ID = BOSS.ORG_ID
WHERE ORI = 3
结果:
+-----+--------+------------+-----+--------+----------+
| ORI | ORG_ID | ORG_PARENT | cnt | ORG_ID | MANAGER |
+-----+--------+------------+-----+--------+----------+
| 3 | 3 | 2 | 1 | NULL | NULL |
| 3 | 2 | 1 | 2 | 2 | Jane Doe |
| 3 | 1 | NULL | 3 | 1 | John Doe |
+-----+--------+------------+-----+--------+----------+