遍历递归 CTE 到 SQL 服务器中的根达到最大递归
traversing recursive CTE to the root in SQL Server reaches maximum recursion
我有一组典型的员工和相应的经理,正如大多数递归 CTE 教程所使用的那样。我从 Uri Dimant
在 tutorial.
的回答中得到的
与深度优先搜索不同,我的目标是输入员工 ID,查询 returns 经理列表直到根 。
因此,我调整了 JOIN 语句以将 manager id
从 CTE 连接到 employee ID
。它应该获取某个员工的经理姓名。
导致错误:
The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
我认为当递归到达管理器的最高级别时,它会 return 一个空的结果集,表明递归结束。
我想了解 SQL 引擎如何知道何时停止。
以及如何使此查询按我的预期工作。
谢谢
IF OBJECT_ID('Employees') IS NULL
BEGIN
CREATE TABLE Employees
(
empid int NOT NULL,
mgrid int NULL,
empname nvarchar(25) NOT NULL,
salary money NOT NULL,
CONSTRAINT PK_Employees PRIMARY KEY(empid),
CONSTRAINT FK_Employees_mgrid_empid
FOREIGN KEY(mgrid)
REFERENCES Employees(empid)
)
CREATE INDEX idx_nci_mgrid ON Employees(mgrid)
SET NOCOUNT ON
INSERT INTO Employees VALUES(1 , NULL, 'Nancy' , 000.00)
INSERT INTO Employees VALUES(2 , 1 , 'Andrew' , 00.00)
INSERT INTO Employees VALUES(3 , 1 , 'Janet' , 00.00)
INSERT INTO Employees VALUES(4 , 1 , 'Margaret', 00.00)
INSERT INTO Employees VALUES(5 , 2 , 'Steven' , 00.00)
INSERT INTO Employees VALUES(6 , 2 , 'Michael' , 00.00)
INSERT INTO Employees VALUES(7 , 3 , 'Robert' , 00.00)
INSERT INTO Employees VALUES(8 , 3 , 'Laura' , 00.00)
INSERT INTO Employees VALUES(9 , 3 , 'Ann' , 00.00)
INSERT INTO Employees VALUES(10, 4 , 'Ina' , 00.00)
INSERT INTO Employees VALUES(11, 7 , 'David' , 00.00)
INSERT INTO Employees VALUES(12, 7 , 'Ron' , 00.00)
INSERT INTO Employees VALUES(13, 7 , 'Dan' , 00.00)
INSERT INTO Employees VALUES(14, 11 , 'James' , 00.00)
END
GO
WITH EmpCTE
AS
(
-- Anchor Member (AM)
SELECT
empid,
empname,
mgrid,
0 AS level -- <------------------- SET LVL START FROM 0
FROM Employees
WHERE EMPID = 7
UNION ALL
-- Recursive Member (RM)
SELECT
e.empid,
e.empname,
e.mgrid,
e.level+1 -- <------------------- INCREMENT LVL
manager id
FROM Employees AS m
JOIN EmpCTE AS e -- <------------------- RECURSIVELY CALL EmpCTE
ON e.mgrid = m.empid
)
SELECT * FROM EmpCTE
您已经成功创建了一个无限循环。您可以针对 level
使用过滤器来调试这些:
(也是在删除 manager id
之后)
WITH EmpCTE
AS
(
-- Anchor Member (AM)
SELECT
empid,
empname,
mgrid,
0 AS level -- <------------------- SET LVL START FROM 0
FROM Employees
WHERE EMPID = 7
UNION ALL
-- Recursive Member (RM)
SELECT
e.empid,
e.empname,
e.mgrid,
e.level+1 -- <------------------- INCREMENT LVL
FROM Employees AS m
JOIN EmpCTE AS e -- <------------------- RECURSIVELY CALL EmpCTE
ON e.mgrid = m.empid
where level < 2
)
SELECT * FROM EmpCTE;
empid empname mgrid level
----------- ------------------------- ----------- -----------
7 Robert 3 0
7 Robert 3 1
7 Robert 3 2
这是因为您投影的是 EmpCTE as e
而不是 Employees as m
的列,所以您只是一次又一次地获得相同的数据(加上级别增加)。
WITH EmpCTE
AS
(
-- Anchor Member (AM)
SELECT
empid,
empname,
mgrid,
0 AS level -- <------------------- SET LVL START FROM 0
FROM Employees
WHERE EMPID = 7
UNION ALL
-- Recursive Member (RM)
SELECT
m.empid, -- these columns need to come from m
m.empname, -- these columns need to come from m
m.mgrid, -- these columns need to come from m
e.level+1 -- <------------------- INCREMENT LVL
FROM Employees AS m
JOIN EmpCTE AS e -- <------------------- RECURSIVELY CALL EmpCTE
ON e.mgrid = m.empid
)
SELECT * FROM EmpCTE;
empid empname mgrid level
----------- ------------------------- ----------- -----------
7 Robert 3 0
3 Janet 1 1
1 Nancy NULL 2
我有一组典型的员工和相应的经理,正如大多数递归 CTE 教程所使用的那样。我从 Uri Dimant
在 tutorial.
与深度优先搜索不同,我的目标是输入员工 ID,查询 returns 经理列表直到根 。
因此,我调整了 JOIN 语句以将 manager id
从 CTE 连接到 employee ID
。它应该获取某个员工的经理姓名。
导致错误:
The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
我认为当递归到达管理器的最高级别时,它会 return 一个空的结果集,表明递归结束。
我想了解 SQL 引擎如何知道何时停止。 以及如何使此查询按我的预期工作。
谢谢
IF OBJECT_ID('Employees') IS NULL
BEGIN
CREATE TABLE Employees
(
empid int NOT NULL,
mgrid int NULL,
empname nvarchar(25) NOT NULL,
salary money NOT NULL,
CONSTRAINT PK_Employees PRIMARY KEY(empid),
CONSTRAINT FK_Employees_mgrid_empid
FOREIGN KEY(mgrid)
REFERENCES Employees(empid)
)
CREATE INDEX idx_nci_mgrid ON Employees(mgrid)
SET NOCOUNT ON
INSERT INTO Employees VALUES(1 , NULL, 'Nancy' , 000.00)
INSERT INTO Employees VALUES(2 , 1 , 'Andrew' , 00.00)
INSERT INTO Employees VALUES(3 , 1 , 'Janet' , 00.00)
INSERT INTO Employees VALUES(4 , 1 , 'Margaret', 00.00)
INSERT INTO Employees VALUES(5 , 2 , 'Steven' , 00.00)
INSERT INTO Employees VALUES(6 , 2 , 'Michael' , 00.00)
INSERT INTO Employees VALUES(7 , 3 , 'Robert' , 00.00)
INSERT INTO Employees VALUES(8 , 3 , 'Laura' , 00.00)
INSERT INTO Employees VALUES(9 , 3 , 'Ann' , 00.00)
INSERT INTO Employees VALUES(10, 4 , 'Ina' , 00.00)
INSERT INTO Employees VALUES(11, 7 , 'David' , 00.00)
INSERT INTO Employees VALUES(12, 7 , 'Ron' , 00.00)
INSERT INTO Employees VALUES(13, 7 , 'Dan' , 00.00)
INSERT INTO Employees VALUES(14, 11 , 'James' , 00.00)
END
GO
WITH EmpCTE
AS
(
-- Anchor Member (AM)
SELECT
empid,
empname,
mgrid,
0 AS level -- <------------------- SET LVL START FROM 0
FROM Employees
WHERE EMPID = 7
UNION ALL
-- Recursive Member (RM)
SELECT
e.empid,
e.empname,
e.mgrid,
e.level+1 -- <------------------- INCREMENT LVL
manager id
FROM Employees AS m
JOIN EmpCTE AS e -- <------------------- RECURSIVELY CALL EmpCTE
ON e.mgrid = m.empid
)
SELECT * FROM EmpCTE
您已经成功创建了一个无限循环。您可以针对 level
使用过滤器来调试这些:
(也是在删除 manager id
之后)
WITH EmpCTE
AS
(
-- Anchor Member (AM)
SELECT
empid,
empname,
mgrid,
0 AS level -- <------------------- SET LVL START FROM 0
FROM Employees
WHERE EMPID = 7
UNION ALL
-- Recursive Member (RM)
SELECT
e.empid,
e.empname,
e.mgrid,
e.level+1 -- <------------------- INCREMENT LVL
FROM Employees AS m
JOIN EmpCTE AS e -- <------------------- RECURSIVELY CALL EmpCTE
ON e.mgrid = m.empid
where level < 2
)
SELECT * FROM EmpCTE;
empid empname mgrid level
----------- ------------------------- ----------- -----------
7 Robert 3 0
7 Robert 3 1
7 Robert 3 2
这是因为您投影的是 EmpCTE as e
而不是 Employees as m
的列,所以您只是一次又一次地获得相同的数据(加上级别增加)。
WITH EmpCTE
AS
(
-- Anchor Member (AM)
SELECT
empid,
empname,
mgrid,
0 AS level -- <------------------- SET LVL START FROM 0
FROM Employees
WHERE EMPID = 7
UNION ALL
-- Recursive Member (RM)
SELECT
m.empid, -- these columns need to come from m
m.empname, -- these columns need to come from m
m.mgrid, -- these columns need to come from m
e.level+1 -- <------------------- INCREMENT LVL
FROM Employees AS m
JOIN EmpCTE AS e -- <------------------- RECURSIVELY CALL EmpCTE
ON e.mgrid = m.empid
)
SELECT * FROM EmpCTE;
empid empname mgrid level
----------- ------------------------- ----------- -----------
7 Robert 3 0
3 Janet 1 1
1 Nancy NULL 2