我正在使用以下公用表表达式来解析自引用表。但CTE不起作用,产生无限循环并产生错误:
Msg 530,Level 16,State 1,Line 1声明终止。该 在语句完成之前,最大递归100已经用尽。
如何修改此CTE以使其正常工作?
SET NOCOUNT ON;
USE tempdb;
IF OBJECT_ID('dbo.Employees', 'U') IS NOT NULL DROP TABLE dbo.Employees;
CREATE TABLE dbo.Employees
(
empid INT NOT NULL PRIMARY KEY,
mgrid INT NULL REFERENCES dbo.Employees,
empname VARCHAR(25) NOT NULL,
salary MONEY NOT NULL,
CHECK (empid > 0)
);
INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES
(1, 1, 'David' , $10000.00),
(2, 1, 'Eitan' , $7000.00),
(3, 1, 'Ina' , $7500.00),
(4, 2, 'Seraph' , $5000.00),
(5, 2, 'Jiru' , $5500.00),
(6, 2, 'Steve' , $4500.00),
(7, 3, 'Aaron' , $5000.00),
(8, 5, 'Lilach' , $3500.00),
(9, 7, 'Rita' , $3000.00),
(10, 5, 'Sean' , $3000.00),
(11, 7, 'Gabriel', $3000.00),
(12, 9, 'Emilia' , $2000.00),
(13, 9, 'Michael', $2000.00),
(14, 9, 'Didi' , $1500.00);
; with Tree as
(
SELECT empid
, mgrid
, 1 as lv
, 1 as level1
, null as level2
, null as level3
, null as level4
, null as level5
FROM Employees
WHERE empid = 1 and mgrid = 1
UNION ALL
SELECT E.empid
, E.mgrid
, T.lv + 1
, T.level1
, case when T.lv = 1 then E.empid else t.level2 end
, case when T.lv = 2 then E.empid else t.level3 end
, case when T.lv = 3 then E.empid else t.level4 end
, case when T.lv = 4 then E.empid else t.level5 end
FROM Employees AS E
JOIN Tree T
ON E.mgrid = T.empid
)
select *
from Tree
order by empid
首选输出
+-------+-------+----+--------+--------+--------+--------+--------+
| empid | mgrid | lv | level1 | level2 | level3 | level4 | level5 |
+-------+-------+----+--------+--------+--------+--------+--------+
| 1 | 1 | 1 | 1 | NULL | NULL | NULL | NULL |
| 2 | 1 | 2 | 1 | 2 | NULL | NULL | NULL |
| 3 | 1 | 2 | 1 | 3 | NULL | NULL | NULL |
| 4 | 2 | 3 | 1 | 2 | 4 | NULL | NULL |
| 5 | 2 | 3 | 1 | 2 | 5 | NULL | NULL |
| 6 | 2 | 3 | 1 | 2 | 6 | NULL | NULL |
| 7 | 3 | 3 | 1 | 3 | 7 | NULL | NULL |
| 8 | 5 | 4 | 1 | 2 | 5 | 8 | NULL |
| 9 | 7 | 4 | 1 | 3 | 7 | 9 | NULL |
| 10 | 5 | 4 | 1 | 2 | 5 | 10 | NULL |
| 11 | 7 | 4 | 1 | 3 | 7 | 11 | NULL |
| 12 | 9 | 5 | 1 | 3 | 7 | 9 | 12 |
| 13 | 9 | 5 | 1 | 3 | 7 | 9 | 13 |
| 14 | 9 | 5 | 1 | 3 | 7 | 9 | 14 |
+-------+-------+----+--------+--------+--------+--------+--------+
答案 0 :(得分:21)
无限循环的原因是empid=mgrid
的第一个记录。要处理此问题,您应该包含一个累积字段(在此示例中为levels
)以存储您已处理的mgrid
,并检查此列表中是否已emid
以避免循环。
这是一个查询:
with Tree as
(
SELECT empid
, mgrid
, 1 as lv
, 1 as level1
, null as level2
, null as level3
, null as level4
, null as level5
, cast(mgrid as varchar(max)) levels
FROM Employees
WHERE empid = 1 and mgrid = 1
UNION ALL
SELECT E.empid
, E.mgrid
, T.lv + 1
, T.level1
, case when T.lv = 1 then E.empid else t.level2 end
, case when T.lv = 2 then E.empid else t.level3 end
, case when T.lv = 3 then E.empid else t.level4 end
, case when T.lv = 4 then E.empid else t.level5 end
, T.levels+','+cast(E.mgrid as varchar(max)) levels
FROM Employees AS E
JOIN Tree T
ON E.mgrid = T.empid
and (','+T.levels+','
not like
'%,'+cast(E.empid as varchar(max))+',%')
)
select *
from Tree
order by empid