这个结果可以通过递归cte来实现吗?

时间:2016-12-01 00:21:59

标签: sql recursion common-table-expression

我目前有一个看起来像这样的表:

| A_URN | B_URN | ID |
|-------|-------|----|
| 101   | 901   | 0  |
|-------|-------|----|
| 102   | 901   | 0  |
|-------|-------|----|
| 101   | 902   | 0  |
|-------|-------|----|
| 102   | 902   | 0  |
|-------|-------|----|
| 201   | 902   | 0  |
|-------|-------|----|
| 201   | 903   | 0  |
|-------|-------|----|
| 202   | 903   | 0  |
|-------|-------|----|
| 301   | 904   | 0  |
|-------|-------|----|
| 302   | 904   | 0  |
|-------|-------|----|
| 301   | 905   | 0  |
|-------|-------|----|
| 302   | 905   | 0  |
|-------|-------|----|
| 303   | 905   | 0  |
|-------|-------|----|
| 101   | 906   | 0  |

我需要添加一个标识符,将所有相关项组合在一起。

例如,A_URN 101连接到B_URN 901,902和906 B_URN 901,902和906还包含A_URN 102和201

A_URN 201也连接到B_URN 903等等。

最终结果应该类似于:

| A_URN | B_URN | ID |
|-------|-------|----|
| 101   | 901   | 1  |
|-------|-------|----|
| 102   | 901   | 1  |
|-------|-------|----|
| 101   | 902   | 1  |
|-------|-------|----|
| 102   | 902   | 1  |
|-------|-------|----|
| 201   | 902   | 1  |
|-------|-------|----|
| 201   | 903   | 1  |
|-------|-------|----|
| 202   | 903   | 1  |
|-------|-------|----|
| 301   | 904   | 2  |
|-------|-------|----|
| 302   | 904   | 2  |
|-------|-------|----|
| 301   | 905   | 2  |
|-------|-------|----|
| 302   | 905   | 2  |
|-------|-------|----|
| 303   | 905   | 2  |
|-------|-------|----|
| 101   | 906   | 1  |

我编写了一个使用WHILE()循环完成此操作的查询,但是已经要求将其重新编写为递归CTE。 我试过了,但总是需要在递归成员中使用MIN或GROUP BY,这是不允许的。

是否可以使用递归查询获得此类结果?

1 个答案:

答案 0 :(得分:0)

如果您需要具有递归CTE的MSSQL解决方案。以下是适合您案例的查询from my answer to the similar question

WITH T as 
(
  SELECT A_URN,B_URN, ROW_NUMBER() OVER (ORDER BY A_URN) as ID FROM Table14
)
,CTE AS 
(
  SELECT CAST(','+CAST(A_URN AS Varchar(100)) +','+ CAST(B_URN as Varchar(100))+',' as Varchar(MAX)) as GroupCont,
        id
  FROM T
  UNION ALL
  SELECT CAST(GroupCont+CAST(A_URN AS Varchar(100)) +','+ CAST(B_URN as Varchar(100))+',' AS Varchar(MAX)) as GroupCont,
         pm.id
  FROM CTE 
  JOIN T as pm
  ON 
     (
       CTE.GroupCont LIKE '%,'+CAST(pm.A_URN AS Varchar(100))+',%'
       OR 
       CTE.GroupCont LIKE '%,'+CAST(pm.B_URN AS Varchar(100))+',%'
     )
     AND NOT  
     (
       CTE.GroupCont LIKE '%,'+CAST(pm.A_URN AS Varchar(100))+',%'
       AND 
       CTE.GroupCont LIKE '%,'+CAST(pm.B_URN AS Varchar(100))+',%'
     )
),
T1 AS 
(
 SELECT pm.A_URN,
       pm.B_URN,  
       ISNULL(
        (SELECT MAX(ID) FROM CTE WHERE 
        (
           CTE.GroupCont LIKE '%,'+CAST(pm.A_URN AS Varchar(100))+',%'
           OR 
           CTE.GroupCont LIKE '%,'+CAST(pm.B_URN AS Varchar(100))+',%'
        ))
        ,pm.ID) as ID
FROM T pm
)

SELECT A_URN,B_URN, 
       DENSE_RANK() OVER (ORDER BY ID) AS ID 
FROM T1
ORDER BY B_URN,A_URN