재귀와 함께 CTE를 사용하지 않습니다. 나는 그것에 관한 기사를 읽고 있었다. 이 문서에서는 SQL 서버 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 문은 한 번만 실행되고 모든 직원 ID를 반환한다고 생각합니다.
그리고 두 번째 쿼리는 반복적으로 실행되어 현재 관리자 ID로 직원이 존재하는 데이터베이스를 쿼리합니다.
SQL 문이 내부 루프에서 어떻게 실행되는지 설명하고 SQL 실행 순서도 알려주십시오. 감사.
나의 2 단계 질문
;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 및 직원 관계의 재귀 :
두 명의 관리자를 추가하고 두 번째 관리자 아래에 몇 명의 직원을 추가하는 순간 문제가 시작됩니다.
첫 번째 관리자 세부 정보를 표시하고 다음 행에는 해당 관리자의 부하 직원과 관련된 직원 세부 정보 만 표시하려고합니다.
가정
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
합니다. 개인 취향의 구문입니다. A의 열을 앨리어싱의 2 가지 주요 방법이 있습니다 CTE
에가 T-SQL
. 나는 간단한의 아날로그 포함 시켰 CTE
에서 Excel
시도하고 무슨 일이 일어나고 있는지 좀 더 친숙한 방법으로 설명하기를.
-- Outside
;WITH CTE (MyColName) AS
(
SELECT 1
)
-- Inside
;WITH CTE AS
(
SELECT 1 AS MyColName
-- Or
SELECT MyColName = 1
-- Etc...
)
Q 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
트리 구조가있는 또 다른 SQL
SELECT ID,space(nLevel+
(CASE WHEN nLevel > 1 THEN nLevel ELSE 0 END)
)+Name
FROM Hierarchy
ORDER BY Family, nLevel
답변
이미 정답에 대한 간략한 의미론을 설명하고 싶습니다.
‘단순한’용어로 재귀 CTE는 의미 론적으로 다음 부분으로 정의 될 수 있습니다.
1 : CTE 쿼리입니다. ANCHOR라고도합니다.
2 : UNION ALL (또는 UNION, EXCEPT 또는 INTERSECT)이있는 (1)의 CTE에 대한 재귀 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은 총 재귀 호출에 대한 모든 튜플을 반환합니다.
추신 : 재귀 적 CTE가 작동하려면 관계에 작업 할 계층 적 (재귀 적) 조건이 있어야합니다. 예 : elementId = elementParentId .. 당신은 요점을 얻습니다.
답변
실행 프로세스는 재귀 CTE와 정말 혼란 스럽습니다. https://technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx 및 CTE 실행 프로세스의 개요 에서 최상의 답변을 찾았습니다. 다음과 같습니다.
재귀 실행의 의미는 다음과 같습니다.
- CTE 식을 앵커 및 재귀 멤버로 분할합니다.
- 첫 번째 호출 또는 기본 결과 세트 (T0)를 작성하는 앵커 멤버를 실행하십시오.
- Ti를 입력으로, Ti + 1을 출력으로 사용하여 재귀 멤버를 실행합니다.
- 빈 세트가 반환 될 때까지 3 단계를 반복합니다.
- 결과 집합을 반환합니다. 이것은 T0에서 Tn까지의 UNION ALL입니다.
답변
--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