在表中找到值的关联

时间:2019-01-03 07:17:47

标签: sql sql-server

我有一张桌子,如下所示。
表格:

LinkA          linkB
--------------------
 1              10
 10             2
 2              5 
 4              7
 6              7
 7              3
 8              2
 3              9

我想在表中找到值的关联。它将链接到具有两个值之一的任何行,然后继续新链接的行。 像这样:

  

第1行(1,10)->第2行(10,2)->第3行(2,5)->第7行(8,2)。 (1)

     

第4行(4,7)->第5行(6,7)->第6行(7,3)->第8行(3,9)。 (2)

如何查询这样的表:

LinkA          linkB     SameLink
-------------------------------
 1              10        1
 10             2         1
 2              5         1
 4              7         2
 6              7         2
 7              3         2
 8              2         1
 3              9         2

测试表:

create table Data(
   linkA INT,
   linkB INT );
insert into Data(linkA, linkB)
values ('1', '10'),('10', '2'),('2', '5'),('4', '7'),('6', '7'),('7', '3'),('8', '2'),('3', '9');

2 个答案:

答案 0 :(得分:1)

使用CTE进行以下查询可以解决您的问题,只需在第一行中设置参数即可:

DECLARE @Start AS INT = 1;
WITH CTE
AS
(
    -- Case Base
    SELECT LinkA, LinkB
    FROM Data E1
    WHERE LinkA = @Start
   UNION ALL
   -- Recursive Branch
    SELECT C.LinkA, E2.LinkB
    FROM CTE C
    INNER JOIN Data E2
        ON  C.LinkB = E2.LinkA
)
SELECT * 
    FROM CTE 
    ORDER BY LinkA, LinkB;

有关Tips 4 DBs的更多详细信息

答案 1 :(得分:0)

我基于SQL cursor

创建了一个解决方案

我还记录了grouping related data into data islands in SQL的解决方案,以提供有关我在下面共享的SQL脚本的更多详细信息

CREATE TABLE RelatedNodes (id int identity(1,1), nodes varchar(max))

DECLARE @LinkA Int
DECLARE @LinkB Int
DECLARE @cnt Int
DECLARE @Nodes1 varchar(max)
DECLARE @Nodes2 varchar(max)
DECLARE @Id1 Int
DECLARE @Id2 Int


DECLARE sqlcursor CURSOR FAST_FORWARD FOR 
select
    LinkA, LinkB
from Data
Order By LinkA, LinkB

OPEN sqlcursor

FETCH NEXT FROM sqlcursor INTO @LinkA, @LinkB

WHILE @@FETCH_STATUS = 0
BEGIN
---
    select 
        Id
    into ##tblId
    from RelatedNodes
    where 
        nodes like ('%,' + convert(varchar(max),@LinkA) + ',%') or 
        nodes like ('%,' + convert(varchar(max),@LinkB) + ',%')

    select @cnt = count(*) from ##tblId

    if @cnt = 0
    begin
        insert into RelatedNodes 
        select 
            case when @LinkA < @LinkB 
                then (',' + convert(varchar(max),@LinkA) + ',' + convert(varchar(max),@LinkB) + ',')
                else (',' + convert(varchar(max),@LinkB) + ',' + convert(varchar(max),@LinkA) + ',')
            end
    end
    else if @cnt = 1
    begin

        update RelatedNodes
        set nodes = nodes + convert(varchar(max),@LinkA) + ',' + convert(varchar(max),@LinkB) + ','
        from RelatedNodes rn
        inner join ##tblId t
            on rn.id = t.id

    end
    else if @cnt = 2
    begin

        select top 1
            @Id1 = rn.Id,
            @Nodes1 = nodes
        from RelatedNodes rn
        inner join ##tblId t
            on rn.id = t.id
        order by t.id

        select top 1
            @Id2 = rn.Id,
            @Nodes2 = nodes 
        from RelatedNodes rn
        inner join ##tblId t
            on rn.id = t.id
        order by t.id desc

        set @Nodes1 = @Nodes1 + @Nodes2

        update RelatedNodes
        set nodes = @Nodes1
        where Id = @Id1

        delete RelatedNodes where Id = @Id2

    end

    drop table ##tblId

    FETCH NEXT FROM sqlcursor INTO @LinkA, @LinkB
END

CLOSE sqlcursor
DEALLOCATE sqlcursor 

select
    LinkA, LinkB, GroupId
from Data
inner join (
    select nodes, ROW_NUMBER() over (order by id) as GroupId from RelatedNodes
) g
on g.nodes like ('%,' + convert(varchar(max),LinkA) + ',%')
Order By GroupId, LinkA, LinkB

执行上述SQL脚本的结果如下,为示例数据的所有行提供数据

enter image description here