2011-09-19 103 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,

列2

显示日e 原始密钥的父节点的sCode,其nNestLevel为1(例外情况,将在一点内得到 ),如果原始ID已经在nNestLevel为1或 0处,它应该打印与第一列相同的sCode。

列3

显示有0 nNestLevel原 密钥的母的的SCODE(有例外,将获得在 位),如果原始ID已经在0的nNestLevel准备好了,应该 再次打印与第一列相同的sCode。


我摸索周围做递归查询窗口,我开始明白如何做到这一点,但问题是有一个例外,那是扔我送行的规则:

如果根父亲kID是10009,则使用nNestLevel 1和2而不是0 ,对于最后两列的规则使用1。

我不知道该如何处理这种特殊情况。


我的解决方案

这是基于关闭马丁·史密斯的答案的解决方案。做了一些小的改动。第一个CTE没有正确传递baseID。最终查询中的select语句还需要进行调整,以便case语句在返回Null之前返回正确的列。

;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

你能澄清这一点:'显示的是具有1 nNestLevel原始密钥的母的的SCODE(有例外,将获得在一个位),如果原来的ID是媒体链接在一个1或0的nNestLevel它应该再次打印与第一列相同的sCode。如果原始密钥的sCode为1,孩子应该在单独的列中显示父代的s代码,还是应该再次显示相同的s代码? – Wil

+0

@Wil sCode是字符串描述。因此,如果作为10283的原始密钥,第一列将是“健康计划诊断”,第二列将是“健康计划诊断”,第三列将是“诊断测试”,前两列是相同的,因为那里10283以下的级别不足以拥有3个不同的名称。 –

回答

1

我觉得像这样的东西应该工作。可能不完全正确,但我会让你排序一个!

;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,但会给你正确的答案。 –