sql server的CTE和recursion的例子
我从不使用recursion的CTE。 我刚刚读了一篇文章。 本文通过Sql服务器CTE和recursion显示员工信息。 这基本上是显示员工和他们的经理信息。 我无法理解这个查询是如何工作的。 这是查询:
WITH cteReports (EmpID, FirstName, LastName, MgrID, EmpLevel) AS ( SELECT EmployeeID, FirstName, LastName, ManagerID, 1 FROM Employees WHERE ManagerID IS NULL UNION ALL SELECT e.EmployeeID, e.FirstName, e.LastName, e.ManagerID, r.EmpLevel + 1 FROM Employees e INNER JOIN cteReports r ON e.ManagerID = r.EmpID ) SELECT FirstName + ' ' + LastName AS FullName, EmpLevel, (SELECT FirstName + ' ' + LastName FROM Employees WHERE EmployeeID = cteReports.MgrID) AS Manager FROM cteReports ORDER BY EmpLevel, MgrID
在这里,我张贴如何输出显示:
我只需要知道它是如何显示经理,然后是他的下属在一个循环。 我想第一个sql语句只触发一次,并返回所有员工的ID。
第二个查询重复触发,用当前经理ID查询哪个员工存在的数据库。
请解释一下sql语句如何在内部循环中执行,并告诉我sql执行顺序。 谢谢。
我的第二个问题的阶段
;WITH Numbers AS ( SELECT n = 1 UNION ALL SELECT n + 1 FROM Numbers WHERE n+1 <= 10 ) SELECT n FROM Numbers
Q 1)N的值是如何递增的? 如果每次将该值分配给N,那么N值可以递增,但是只有第一次N值被初始化。
问2)CTE和员工关系的recursion:
当我添加两名经理并在第二位经理下增加几名员工的时候,就是问题出现的地方。
我想显示第一个经理的详细信息,并在下一行中显示与该经理的下属相关的员工详细信息。
假设
ID Name MgrID Level --- ---- ------ ----- 1 Keith NULL 1 2 Josh 1 2 3 Robin 1 2 4 Raja 2 3 5 Tridip NULL 1 6 Arijit 5 2 7 Amit 5 2 8 Dev 6 3
我想用CTEexpression式以这种方式显示结果。 请告诉我在我为了拉取经理 – 雇员关系而在这里给我的sql中修改了什么。 谢谢。
我想输出是这样的:
ID Name MgrID nLevel Family ----------- ------ ----------- ----------- -------------------- 1 Keith NULL 1 1 3 Robin 1 2 1 2 Josh 1 2 1 4 Raja 2 3 1 5 Tridip NULL 1 2 7 Amit 5 2 2 6 Arijit 5 2 2 8 Dev 6 3 2
这可能吗…?
我没有testing过你的代码,只是试图帮助你理解它在评论中是如何运作的。
WITH cteReports (EmpID, FirstName, LastName, MgrID, EmpLevel) AS ( -->>>>>>>>>>Block 1>>>>>>>>>>>>>>>>> -- In a rCTE, this block is called an [Anchor] -- The query finds all root nodes as described by WHERE ManagerID IS NULL SELECT EmployeeID, FirstName, LastName, ManagerID, 1 FROM Employees WHERE ManagerID IS NULL -->>>>>>>>>>Block 1>>>>>>>>>>>>>>>>> UNION ALL -->>>>>>>>>>Block 2>>>>>>>>>>>>>>>>> -- This is the recursive expression of the rCTE -- On the first "execution" it will query data in [Employees], -- relative to the [Anchor] above. -- This will produce a resultset, we will call it R{1} and it is JOINed to [Employees] -- as defined by the hierarchy -- Subsequent "executions" of this block will reference R{n-1} SELECT e.EmployeeID, e.FirstName, e.LastName, e.ManagerID, r.EmpLevel + 1 FROM Employees e INNER JOIN cteReports r ON e.ManagerID = r.EmpID -->>>>>>>>>>Block 2>>>>>>>>>>>>>>>>> ) SELECT FirstName + ' ' + LastName AS FullName, EmpLevel, (SELECT FirstName + ' ' + LastName FROM Employees WHERE EmployeeID = cteReports.MgrID) AS Manager FROM cteReports ORDER BY EmpLevel, MgrID
我能想到的一个recursionCTE
的最简单的例子来说明它的操作。
;WITH Numbers AS ( SELECT n = 1 UNION ALL SELECT n + 1 FROM Numbers WHERE n+1 <= 10 ) SELECT n FROM Numbers
问1)N的值是如何递增的。 如果每次将值分配给N,则N值可以递增,但是只有第一次N值被初始化 。
A1:
在这种情况下, N
不是一个variables。 N
是一个别名。 这相当于SELECT 1 AS N
这是个人喜好的句法。 在T-SQL
CTE
中有两个主要的混淆列的方法。 我在Excel
包含了一个简单的CTE
的模拟,以更熟悉的方式尝试和说明正在发生的事情。
-- Outside ;WITH CTE (MyColName) AS ( SELECT 1 ) -- Inside ;WITH CTE AS ( SELECT 1 AS MyColName -- Or SELECT MyColName = 1 -- Etc... )
Q 2)现在这里关于CTE和员工关系的recursion当我添加两个经理并在第二个经理下添加更多的员工然后问题开始。 我想显示第一个经理的详细信息,在下一行中,只有那些经理的下属员工的详细信息
A2:
这个代码是否回答你的问题?
-------------------------------------------- -- Synthesise table with non-recursive CTE -------------------------------------------- ;WITH Employee (ID, Name, MgrID) AS ( SELECT 1, 'Keith', NULL UNION ALL SELECT 2, 'Josh', 1 UNION ALL SELECT 3, 'Robin', 1 UNION ALL SELECT 4, 'Raja', 2 UNION ALL SELECT 5, 'Tridip', NULL UNION ALL SELECT 6, 'Arijit', 5 UNION ALL SELECT 7, 'Amit', 5 UNION ALL SELECT 8, 'Dev', 6 ) -------------------------------------------- -- Recursive CTE - Chained to the above CTE -------------------------------------------- ,Hierarchy AS ( -- Anchor SELECT ID ,Name ,MgrID ,nLevel = 1 ,Family = ROW_NUMBER() OVER (ORDER BY Name) FROM Employee WHERE MgrID IS NULL UNION ALL -- Recursive query SELECT E.ID ,E.Name ,E.MgrID ,H.nLevel+1 ,Family FROM Employee E JOIN Hierarchy H ON E.MgrID = H.ID ) SELECT * FROM Hierarchy ORDER BY Family, nLevel
另一个与树结构的SQL
SELECT ID,space(nLevel+ (CASE WHEN nLevel > 1 THEN nLevel ELSE 0 END) )+Name FROM Hierarchy ORDER BY Family, nLevel
想要概括一个与已经正确答案相似的简短语义。
在“简单”的术语中,recursionCTE可以在语义上定义为以下部分:
1:CTE查询。 也被称为ANCHOR。
2:使用UNION ALL(或UNION或EXCEPT或INTERSECT)在(1)中的CTE上进行recursionCTE查询,因此返回最终结果。
3:angular落/终止条件。 当recursion查询返回没有更多的行/元组时,默认情况下是这样的。
一个简短的例子,将使图片清晰:
;WITH SupplierChain_CTE(supplier_id, supplier_name, supplies_to, level) AS ( SELECT S.supplier_id, S.supplier_name, S.supplies_to, 0 as level FROM Supplier S WHERE supplies_to = -1 -- Return the roots where a supplier supplies to no other supplier directly UNION ALL -- The recursive CTE query on the SupplierChain_CTE SELECT S.supplier_id, S.supplier_name, S.supplies_to, level + 1 FROM Supplier S INNER JOIN SupplierChain_CTE SC ON S.supplies_to = SC.supplier_id ) -- Use the CTE to get all suppliers in a supply chain with levels SELECT * FROM SupplierChain_CTE
说明:第一个CTE查询返回不直接提供给任何其他供应商的基础供应商(如叶)(-1)
在第一次迭代中的recursion查询得到所有供应给由ANCHOR返回的供应商的供应商。 这个过程继续,直到条件返回元组。
UNION ALL返回全部recursion调用的所有元组。
另一个很好的例子可以在这里find。
PS:对于recursionCTE的工作,关系必须有一个分层(recursion)的条件来进行工作。 例如:elementId = elementParentId ..你明白了。
执行过程真的与recursionCTE混淆,我发现最好的答案在https://technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx和CTE执行过程的摘要如下所示。
recursion执行的语义如下:
- 将CTEexpression式分解为锚和recursion成员。
- 运行创build第一个调用或基本结果集(T0)的定位成员。
- 以Ti作为input,Ti + 1作为输出运行recursion成员。
- 重复步骤3,直到返回空集。
- 返回结果集。 这是T0到Tn的联盟。
--DROP TABLE #Employee CREATE TABLE #Employee(EmpId BIGINT IDENTITY,EmpName VARCHAR(25),Designation VARCHAR(25),ManagerID BIGINT) INSERT INTO #Employee VALUES('M11M','Manager',NULL) INSERT INTO #Employee VALUES('P11P','Manager',NULL) INSERT INTO #Employee VALUES('AA','Clerk',1) INSERT INTO #Employee VALUES('AB','Assistant',1) INSERT INTO #Employee VALUES('ZC','Supervisor',2) INSERT INTO #Employee VALUES('ZD','Security',2) SELECT * FROM #Employee (NOLOCK) ; WITH Emp_CTE AS ( SELECT EmpId,EmpName,Designation, ManagerID ,CASE WHEN ManagerID IS NULL THEN EmpId ELSE ManagerID END ManagerID_N FROM #Employee ) select EmpId,EmpName,Designation, ManagerID FROM Emp_CTE order BY ManagerID_N, EmpId