CTEを再帰で使用することはありません。私はそれについての記事を読んでいた。この記事では、SQL Server CTEと再帰の助けを借りて従業員情報を示します。基本的に従業員とそのマネージャーの情報を表示しています。このクエリの仕組みを理解できません。クエリは次のとおりです。
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ステートメントは1回だけ起動し、すべての従業員IDを返します。
そして、2番目のクエリが繰り返し起動され、従業員が存在するデータベースに現在のマネージャ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値が最初に初期化されたときだけです。
Q 2)CTEと従業員関係の再帰:
2人のマネージャーを追加し、2人目のマネージャーの下にさらに数人の従業員を追加すると、問題が発生します。
最初のマネージャーの詳細を表示し、次の行にはそのマネージャーの部下に関連する従業員の詳細のみを表示します。
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
このような方法でCTE式を使用して結果を表示したいと思います。マネージャーと従業員の関係を引き出すために、ここで提供した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
これは可能ですか...?
私はあなたのコードをテストしていません。コメントでそれがどのように動作するかをあなたが理解するのを助けようとしました。
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
再帰的なCTE
の最も単純な例は、その動作を説明するために考えることができます。
;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値が初期化されたときのみです。
A1:
この場合、N
は変数ではありません。 N
はエイリアスです。これはSELECT 1 AS N
と同等です。これは個人的な好みの構文です。 T-SQL
のCTE
の列に別名を付けるには、主に2つの方法があります。 CTE
に単純なExcel
の類似物を含めて、何が起こっているのかをより身近な方法で説明しようとしています。
-- Outside
;WITH CTE (MyColName) AS
(
SELECT 1
)
-- Inside
;WITH CTE AS
(
SELECT 1 AS MyColName
-- Or
SELECT MyColName = 1
-- Etc...
)
Q 2)ここで、2人のマネージャーを追加し、2人目のマネージャーの下に従業員をもう少し追加して、問題を開始した瞬間のCTEと従業員関係の再帰について説明します。最初のマネージャーの詳細を表示し、次の行にはそのマネージャーの部下である従業員の詳細のみが表示されます
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
SELECT ID,space(nLevel+
(CASE WHEN nLevel > 1 THEN nLevel ELSE 0 END)
)+Name
FROM Hierarchy
ORDER BY Family, nLevel
すでに正解と平行した簡単なセマンティックの概要を説明します.
「単純な」用語では、再帰的CTEは次の部分として意味的に定義できます。
1:CTEクエリ。アンカーとも呼ばれます。
2:(1)のCTEでのUNION ALL(またはUNIONまたはEXCEPTまたはINTERSECT)を使用した再帰CTEクエリ。したがって、最終結果が適宜返されます。
3:コーナー/終端条件。これは、再帰クエリによって返される行/タプルがなくなったときのデフォルトです。
画像を明確にする短い例:
;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)
最初の反復の再帰クエリは、ANCHORによって返されたサプライヤに供給するすべてのサプライヤを取得します。このプロセスは、条件がタプルを返すまで続きます。
UNION ALLは、再帰呼び出し全体のすべてのタプルを返します。
別の良い例は here にあります。
PS:再帰CTEが機能するには、リレーションに機能する階層(再帰)条件が必要です。例:elementId = elementParentId ..ポイントを取得します。
実行プロセスは再帰的なCTEとは本当に混乱します。私は https://technet.Microsoft.com/en-us/library/ms186243(v = sql.105).aspx で最良の答えを見つけましたCTE実行プロセスの概要は次のとおりです。
再帰的実行のセマンティクスは次のとおりです。