繁体   English   中英

SQL自递归加入分组

[英]SQL Self Recursive Join with Grouping

在 SQL Server 中,我有下表:

Name   New_Name 
---------------
A         B
B         C
C         D
G         H
H         I
Z         B

我想创建一个新表,该表链接与单个新 groupID 相关的所有名称

GroupID  Name
-------------
1         A
1         B
1         C
1         D
1         Z
2         G
2         H
2         I

除了一堆连接之外,我有点无法弄清楚如何做到这一点。 但我想正确地做到这一点。

编辑了问题以允许从两个不同的起点 A 和 Z 分组为一组。

由于您已更改问题,因此我正在更新答案。 请注意,答案在逻辑结构上是相同的。 它所做的不同之处在于,不是在计算级别时从 G 到 I,而是现在从 I 计算到 G。

工作演示链接

;with cte as
( 
    select 
       t1.Name as Name, row_number() over (order by t1.Name) r,
       t1.New_Name as New_Name,
       1 as level 
    from yt t1 left join  yt t2
       on t1.New_Name=t2.name
    where t2.name is null
     union all
    select 
       yt.Name as Name, r,
       yt.New_Name as New_Name,
       c.level+1 as level
    from cte c  join yt
       on yt.New_Name=c.Name
   ),
   cte2 as 
   (   
     select r as group_id, Name from cte
     union
     select c1.r as group_id, c1.New_name as Name from cte c1
       where level = (select min(level) from cte c2 where c2.r=c1.r)
     )


 select * from cte2;

以下是旧答案。

您可以尝试以下基于 CTE 的查询:

create table yt (Name varchar(10),  New_Name varchar(10));
insert into yt values
('A','B'),
('B','C'),
('C','D'),
('G','H'),
('H','I');

;with cte as
( 
    select 
       t1.Name as Name, row_number() over (order by t1.Name) r,
       t1.New_Name as New_Name,
       1 as level 
    from yt t1 left join  yt t2
       on t1.Name=t2.New_name
    where t2.new_name is null
     union all
    select 
       yt.Name as Name, r,
       yt.New_Name as New_Name,
       c.level+1 as level
    from cte c  join yt
       on yt.Name=c.New_Name
   ),
 cte2 as 
 (   
   select r as group_id, Name from cte
   union
   select c1.r as group_id, c1.New_name as Name from cte c1
     where level = (select max(level) from cte c2 where c2.r=c1.r)
   )


 select * from cte2;

见工作演示

有点复杂但有效。

DECLARE @T TABLE  (Name VARCHAR(2),   New_Name VARCHAR(2))
INSERT INTO @T
VALUES
('A','B'),
('B','C'),
('C','D'),
('G','H'),
('H','I'),
('Z','B')

;WITH CTE AS
(
    SELECT * , RN = ROW_NUMBER() OVER(ORDER BY Name) FROM @T
)
,CTE2 AS (SELECT T1.RN, T1.Name Name1, T1.New_Name New_Name1, 
                 X.Name Name2, X.New_Name New_Name2, 
                 FLAG = CASE WHEN X.Name  IS NULL THEN 1 ELSE 0 END 
          FROM CTE T1
          OUTER APPLY (SELECT  * FROM CTE T2 WHERE T2.RN > T1.RN 
                       AND (T2.Name IN (T1.Name , T1.New_Name) 
                            OR T2.New_Name IN (T1.Name , T1.New_Name)
                       ))  AS X
)
,CTE3 AS (SELECT *, 
    GroupID = ROW_NUMBER() OVER (ORDER BY RN) -
          ROW_NUMBER() OVER (PARTITION BY Flag ORDER BY RN) +1
    FROM CTE2
)
SELECT 
    DISTINCT GroupID, Name 
FROM 
  (SELECT * FROM CTE3 WHERE Name2 IS NOT NULL) SRC 
  UNPIVOT ( Name FOR COL IN ([Name1], [New_Name1], [Name2], [New_Name2])) UNPVT

结果

GroupID              Name
-------------------- ----
1                    A
1                    B
1                    C
1                    D
1                    Z
2                    G
2                    H
2                    I

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM