2011-09-19 2 views
1

이상한 디자인 요구 사항이 있습니다. 다음은 내가 작업하고있는 예제 표입니다.여러 열의 값을 채우는 재귀적인 SQL

DECLARE @T TABLE 
(
kID INT, 
sCode VARCHAR(50), 
kParentID INT NULL, 
nNestLevel INT 
) 

INSERT INTO @T 
SELECT 10009,'Professional Fees    ',NULL ,0 UNION ALL 
SELECT 10371,'Exam Room Fees     ',10009 ,1 UNION ALL 
SELECT 10410,'Diagnostic Tests    ',NULL ,0 UNION ALL 
SELECT 10011,'Pharmacy Income    ',NULL ,0 UNION ALL 
SELECT 10395,'Dietary Products    ',NULL ,0 UNION ALL 
SELECT 10053,'Outpatient Services & Treatment',10371 ,2 UNION ALL 
SELECT 10055,'Canine Vaccines    ',10371 ,2 UNION ALL 
SELECT 10200,'Office Calls and Exams   ',10371 ,2 UNION ALL 
SELECT 10204,'Feline Vaccines    ',10371 ,2 UNION ALL 
SELECT 10205,'Ferret Vaccines    ',10371 ,2 UNION ALL 
SELECT 10206,'Euthanasia      ',10371 ,2 UNION ALL 
SELECT 10207,'Cremation & Burial    ',10371 ,2 UNION ALL 
SELECT 10304,'Laser Therapy     ',10371 ,2 UNION ALL 
SELECT 10379,'Hospitalization & Inpatient Ser',10371 ,2 UNION ALL 
SELECT 10283,'Wellness Plan Diagnostics  ',10410 ,1 UNION ALL 
SELECT 10411,'Opthalmic Tests    ',10410 ,1 UNION ALL 
SELECT 10412,'Blood Pressure     ',10410 ,1 UNION ALL 
SELECT 10413,'Diagnostic Other Tests   ',10410 ,1 UNION ALL 
SELECT 10414,'EKG       ',10410 ,1 UNION ALL 
SELECT 10267,'In Hospital Pharmacy   ',10011 ,1 UNION ALL 
SELECT 10368,'Parasiticides     ',10011 ,1 UNION ALL 
SELECT 10383,'Outpatient Pharmacy   ',10011 ,1 UNION ALL 
SELECT 10013,'Prescription Diets    ',10395 ,1 UNION ALL 
SELECT 10021,'Non Prescription Diets   ',10395 ,1 UNION ALL 
SELECT 10083,'Inpatient Medical Services & Tx',10379 ,3 UNION ALL 
SELECT 10201,'Outpatient Treatments   ',10053 ,3 UNION ALL 
SELECT 10280,'Herbal & Acupuncture Exams  ',10200 ,3 UNION ALL 
SELECT 10295,'Hospital Tasks Income   ',10379 ,3 UNION ALL 
SELECT 10308,'Distemper/Parvo    ',10055 ,3 UNION ALL 
SELECT 10309,'Bordetella      ',10055 ,3 

각 항목은 다음 레벨의 상위를 가리 킵니다. 나는이 일을 참조하고, 내가 그 테이블에 세 개의 열을 추가 할 필요가 외래 키로 아이를 사용하는 다른 테이블을 기반으로 쿼리,

열 1

쇼를 만들기 위해 필요한 것 외부 키의 SCODE,

열이

표시 일 원래의 ID가 1의 nNestLevel 또는 0 인 경우 예외를 가지고 이 될 것입니다.) 0의 nNestLevel을 가진 원래 키의 부모의 sCode는 첫 번째 열과 동일한 sCode. 3 열

0의 nNestLevel을 가지고 원래 키의 부모하여 SCODE보기, 경우 (A 예외를 에서 그에게 조금을 얻을 것이다) 원래 ID는 0의 nNestLevel에 있습니다. 은 동일한 sCode를 첫 번째 열로 다시 인쇄해야합니다.

: 나는 주위 멍청이 재귀 룩 - 업을하고 내가 그러나 문제가있다, 그것을 수행하는 방법을 이해하기 시작하고 있어요


날을 던지고 규칙에 대한 예외

루트 부모 kID가 10009 인 경우 0 대신 nNestLevel 1과 2를 사용하고 마지막 두 열의 규칙에 1을 사용합니다.

나는이 특별한 경우를 어떻게 처리해야할지 모르겠다.


내 솔루션 여기

마틴 스미스의 대답 기반으로 솔루션입니다. 몇 가지 작은 변경 사항이 있습니다. 첫 번째 CTE가 baseID를 올바르게 전달하지 못했습니다. 최종 쿼리의 select 문도 조정해야하므로 Null을 반환 할 가능성이 있기 전에 case 문이 올바른 열을 반환합니다.

;WITH R AS 
(
SELECT * , 1 AS L, kID AS BasekID 
FROM Accounts 
UNION ALL 
SELECT T.*, L+1, R.BasekID 
FROM Accounts T JOIN R ON T.kID = R.kParentID 
), T AS 
(
SELECT BasekID AS kID, 
     MAX(CASE WHEN L=1 THEN sCode END) AS sCode, 
     MAX(CASE WHEN L=1 THEN nNestLevel END) AS nNestLevel,  
     MAX(CASE WHEN nNestLevel =0 THEN sCode END) AS sCode0, 
     MAX(CASE WHEN nNestLevel =1 THEN sCode END) AS sCode1, 
     MAX(CASE WHEN nNestLevel =2 THEN sCode END) AS sCode2, 
     MAX(CASE WHEN nNestLevel =0 THEN kID END) AS RootkID 
FROM R 
GROUP BY BasekID 
) 
    SELECT kID, sCode AS Col1, 
     --This case statement is to handel when the rootkID is 10009, we should go up a level if it is. 
    CASE WHEN nNestLevel <= 1 AND RootkID <> 10009 THEN sCode 
     WHEN nNestLevel <= 2 AND RootkID = 10009 THEN sCode 
     WHEN RootkID = 10009 THEN sCode2 
     ELSE sCode1 END AS Col2, 
    CASE WHEN nNestLevel <= 0 AND RootkID <> 10009 THEN sCode 
     WHEN nNestLevel <= 1 AND RootkID = 10009 THEN sCode 
     WHEN RootkID = 10009 THEN sCode1 
     ELSE sCode0 END AS Col3 
FROM T 
+0

당신은이를 명확히 할 수 nNestLevel이 1 또는 0이면 첫 번째 열과 동일한 sCode를 다시 인쇄해야합니다. '원래 키의 sCode가 1 인 경우 자식이 sCode를 별도의 열에 표시해야합니까? 아니면 동일한 sCode를 다시 표시해야합니까? – Wil

+0

@Wil sCode는 문자열 설명입니다. 따라서 10283의 forgen 키가있는 경우 첫 번째 열은 "Wellness Plan Diagnostics"이고 seccond 열은 "Wellness Plan Diagnostics"가되고 세 번째 열은 "Diagnostic Tests"가됩니다. 처음 두 열은 동일하기 때문에 10283 아래에 3 개의 고유 한 이름을 갖는 수준이 충분하지 않습니다. –

답변

1

이렇게 생각하면됩니다. 정확하게 맞지는 않을지 몰라도, 나는 그것을 밖으로 분류하도록 할 것입니다!원래 ID가에 allready 경우, (하는 예외를 가지는 비트에 그에게 얻을 것이다) (1)의 nNestLevel을 가지고 원래 키의 부모하여 SCODE보기`:

;WITH R AS 
(
SELECT * , 1 AS L, kID AS BasekID 
FROM @T 
UNION ALL 
SELECT T.*, L+1, R.kID 
FROM @T T JOIN R ON T.kID = R.kParentID 
), T AS 
(
SELECT BasekID AS kID, 
     MAX(CASE WHEN L=1 THEN sCode END) AS sCode, 
     MAX(CASE WHEN L=1 THEN nNestLevel END) AS nNestLevel,  
     MAX(CASE WHEN nNestLevel =0 THEN sCode END) AS sCode0, 
     MAX(CASE WHEN nNestLevel =1 THEN sCode END) AS sCode1, 
     MAX(CASE WHEN nNestLevel =2 THEN sCode END) AS sCode2, 
     MAX(CASE WHEN nNestLevel =0 THEN kID END) AS RootkID 
FROM R 
GROUP BY BasekID 
) 
    SELECT sCode AS Col1, 
     CASE WHEN nNestLevel <=1 AND RootkID <> 10009 THEN sCode 
      WHEN nNestLevel <=1 AND RootkID = 10009 THEN sCode2 
      ELSE sCode1 END AS Col2, 
     CASE WHEN nNestLevel =0 AND RootkID <> 10009 THEN sCode 
      WHEN nNestLevel =0 AND RootkID = 10009 THEN sCode1 
      ELSE sCode0 END AS Col3 
FROM T 
+1

내가 겪고있는 문제는 R 블록에 있습니다. 각 반복의 BaseID는 이전 반복의 kID를 기반으로합니다. 내가 필요로하는 것은 그것이 L = 1의 kID가되는 것입니다. 문제를 해결하기 위해'SELECT T. *, L + 1, R.kID'를'SELECT T. *, L + 1, R.BasekID'로 변경했습니다. 또한 10009 케이스에 몇 가지 문제가있었습니다. OP를 완성 된 쿼리로 업데이트 하겠지만 정확한 답 신용을 줄 것입니다. –