所有Child for Multiple parent的CTE

时间:2016-08-25 06:03:53

标签: sql recursion common-table-expression

我有一个父子关系表,如下所示:

ContractID        ContractIdRef
----------        -------------
 1                 null
 2                 1
 3                 1
 4                 2
 5                 4
 10                null
 11                10
 12                11
 15                null
 16                12

我想要如下结果:

 ContractID        ContractIdRef    rw
-----------        --------------   ---
 1                 null             1
 2                 1                1
 3                 1                1
 4                 2                1
 5                 4                1
 10                null             10
 11                10               10
 12                11               10
 15                null             15
 16                12               10

在上面的结果中,我想指定父行的每一行。
感谢

2 个答案:

答案 0 :(得分:2)

正如您在 TAGS Comman Table Expression中所提到的那样

;WITH REC_CTE 
     AS (SELECT [contractid], 
                [ContractIdRef], 
                [contractid] AS rw
         FROM   Yourtable
         WHERE  [contractidref] IS NULL 
         UNION ALL 
         SELECT T.[contractid], 
                T.[contractidref], 
                c.rw
         FROM   Yourtable AS T 
                INNER JOIN REC_CTE C 
                        ON T.[contractidref] = c.[contractid] 
         WHERE  T.[contractid] <> T.[contractidref]) 
SELECT [contractid], 
       [contractidref],
       rw
FROM   REC_CTE 
ORDER  BY [contractid] 

演示

架构设置

If object_id('tempdb.dbo.#Yourtable') is not null
DROP table #Yourtable

CREATE TABLE #Yourtable
    ([ContractID] INT, [ContractIdRef] INT);

示例数据

INSERT INTO #Yourtable
    ([ContractID], [ContractIdRef])
VALUES
    ('1', NULL),
    ('2', '1'),
    ('3', '1'),
    ('4', '2'),
    ('5', '4'),
    ('10', NULL),
    ('11', '10'),
    ('12', '11'),
    ('15', NULL),
    ('16', '12');

查询

;WITH REC_CTE
     AS (SELECT [ContractID], 
                [ContractIdRef] as [ContractIdRef],
                [ContractID] AS rw 
         FROM   #Yourtable where [ContractIdRef] is null

         UNION ALL 
         SELECT T.[ContractID], 
                T.[ContractIdRef], 
                c.rw 
         FROM   #Yourtable  AS T 
                INNER JOIN REC_CTE c 
                        ON T.[ContractIdRef] = c.[ContractID] 
         WHERE  T.[ContractID] <> T.[ContractIdRef]) 
SELECT [ContractID], 
       [ContractIdRef],
       rw 
FROM   REC_CTE 
ORDER  BY [ContractID]  

结果

+-----------+-------------+----+
|ContractID |ContractIdRef| rw |
+-----------+-------------+----+
|1          |NULL         | 1  |
|2          |1            | 1  |
|3          |1            | 1  |
|4          |2            | 1  |
|5          |4            | 1  |
|10         |NULL         | 10 |
|11         |10           | 10 |
|12         |11           | 10 |
|15         |NULL         | 15 |
|16         |12           | 10 |
+-----------+-------------+----+    

答案 1 :(得分:0)

with Q as(
  select ContractID, ContractIdRef, ContractID as root
    from childs
   where ContractIdRef is null
 union all
  select C.ContractID, C.ContractIdRef, Q.root
    from Q, childs C
   where C.ContractIdRef=Q.ContractID
)
select * from Q
 order by ContractID

在MS SQL 2014上测试。

对于Postgresql,需要在'with'后添加'递归'字样。 Test on sqlfiddle.com

对于Oracle第一行写为with Q(ContractID,ContractIdRef,root)