我正在使用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_IDAGERS表重复查询ORG_ID = 2并在此示例中返回“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 声明终止。在语句完成之前,最大递归100已经用尽。
MANAGER ORG_ID ORG_PARENT
NULL 3 2
答案 0 :(得分:2)
您需要跟踪您开始使用的原始ID。试试这个:
function mixIt<A, B> (a: A, b: B): A & B;
function mixIt<A, B, C>(a: A, b: B, c: C): A & B & C;
function mixIt<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D;
function mixIt<A, B, C, D, E>(a: A, b: B, c: C, d: D, e: E): A & B & C & D & E;
function mixIt<A, B, C, D, E, F>(a: A, b: B, c: C, d: D, e: E, f: F): A & B & C & D & E &F ;
// Private signature
function mixIt(...args: any[]): any{ // no need for this to be generic
let mixin: any = {};
args.forEach( obj => {
for(let key in obj) {
if( ! mixin.hasOwnProperty(key) ) {
mixin[key] = obj[key];
}
}
});
return mixin;
}
结果:
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
一般提示:
不要预定义CTE的列;它没有必要,并且使维护变得烦人。
使用递归CTE,始终保留一个计数器,这样就可以限制递归,并且可以跟踪你的深度。
修改强>
顺便说一句,如果你想要第一个非空管理器,你可以这样做(有很多方法):
+----------+-----+--------+------------+-----+
| MANAGER | ORI | ORG_ID | ORG_PARENT | cnt |
+----------+-----+--------+------------+-----+
| NULL | 3 | 3 | 2 | 1 |
| Jane Doe | 3 | 2 | 1 | 2 |
| John Doe | 3 | 1 | NULL | 3 |
+----------+-----+--------+------------+-----+