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... ) 

Excel_CTE

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执行的语义如下:

  1. 将CTEexpression式分解为锚和recursion成员。
  2. 运行创build第一个调用或基本结果集(T0)的定位成员。
  3. 以Ti作为input,Ti + 1作为输出运行recursion成员。
  4. 重复步骤3,直到返回空集。
  5. 返回结果集。 这是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