查找所有匹配标识符的递归SQL查询

查找所有匹配标识符的递归SQL查询,sql,sql-server,sql-server-2012,recursive-query,Sql,Sql Server,Sql Server 2012,Recursive Query,我有一张有以下结构的桌子 CREATE TABLE Source ( [ID1] INT, [ID2] INT ); INSERT INTO Source ([ID1], [ID2]) VALUES (1, 2), (2, 3), (4, 5), (2, 5), (6, 7) 源表和结果表示例: 源表基本上存储哪个id与另一个id匹配。从图中可以看出,1、2、3、4、5是相同的。和6,7是相同的。我需要一个SQL查询来获得一个包含ID之间所有匹配项的结果

我有一张有以下结构的桌子

CREATE TABLE Source
(
     [ID1] INT, 
     [ID2] INT
);

INSERT INTO Source ([ID1], [ID2]) 
VALUES (1, 2), (2, 3), (4, 5),
       (2, 5), (6, 7)
源表和结果表示例:

源表基本上存储哪个id与另一个id匹配。从图中可以看出,1、2、3、4、5是相同的。和6,7是相同的。我需要一个SQL查询来获得一个包含ID之间所有匹配项的结果表

我在网站上找到了这个项目- 与我的任务类似,但结果不同

我试图为我的任务编辑代码,但它不起作用。声明终止了。在语句完成之前,已耗尽最大递归100

;WITH CTE
AS
(
    SELECT DISTINCT
        M1.ID1,
        M1.ID1 as ID2
    FROM Source M1
        LEFT JOIN Source M2
            ON M1.ID1 = M2.ID2
    WHERE M2.ID2 IS NULL
    UNION ALL
    SELECT
        C.ID2,
        M.ID1
    FROM CTE C
        JOIN Source M
            ON C.ID1 = M.ID1
)
SELECT * FROM CTE ORDER BY ID1

非常感谢你的帮助

这是一种通过蛮力获得输出的方法,但对于不同/更大的数据集,可能不是最好的解决方案:

select sub1.rnk as ID1
,sub2.rnk as ID2
from
(
select a.*
,rank() over (partition by 1 order by id1, id2) as RNK
from source a
) sub1
cross join
(
select a.*
,rank() over (partition by 1 order by id1, id2) as RNK
from source a
) sub2
where sub1.rnk <> sub2.rnk
union all
select id1 as ID1
,id2 as ID2
from source
where id1 = 6
union all
select id2 as ID1
,id1 as ID2
from source
where id1 = 6;

这是一个具有挑战性的问题。您正试图从两个方向浏览图形。有两个关键想法:

添加反向边,使图形的行为类似于有向图,但在两个方向上都有边。 保留已访问的边的列表。在SQL Server中,字符串是一种方法。 因此:

这是一本书

由于所有节点连接都是双向的,因此将反向关系添加到原始列表中 从每个节点找到所有可能的路径;几乎是常见的递归,唯一的区别是-我们需要保持根id1 避免循环-我们需要意识到这一点,因为我们没有方向 资料来源:

;with src as(
  select id1, id2 from source
  union 
  -- reversed connections
  select id2, id1 from source
), rec as (
  select id1, id2, CAST(CONCAT('/', src.id1, '/', src.id2, '/') as varchar(8000)) path
  from src

  union all

  -- keep the root id1 from the start of each path
  select rec.id1, src.id2, CAST(CONCAT(rec.path, src.id2, '/') as varchar(8000))
  from rec
  -- usual recursion
  inner join src on src.id1 = rec.id2
  -- avoid cycles
  where rec.path not like CONCAT('%/', src.id2, '/%')
)
select id1, id2, path 
from rec
order by 1, 2
输出

| id1 | id2 |      path |
|-----|-----|-----------|
|   1 |   2 |     /1/2/ |
|   1 |   3 |   /1/2/3/ |
|   1 |   4 | /1/2/5/4/ |
|   1 |   5 |   /1/2/5/ |
|   2 |   1 |     /2/1/ |
|   2 |   3 |     /2/3/ |
|   2 |   4 |   /2/5/4/ |
|   2 |   5 |     /2/5/ |
|   3 |   1 |   /3/2/1/ |
|   3 |   2 |     /3/2/ |
|   3 |   4 | /3/2/5/4/ |
|   3 |   5 |   /3/2/5/ |
|   4 |   1 | /4/5/2/1/ |
|   4 |   2 |   /4/5/2/ |
|   4 |   3 | /4/5/2/3/ |
|   4 |   5 |     /4/5/ |
|   5 |   1 |   /5/2/1/ |
|   5 |   2 |     /5/2/ |
|   5 |   3 |   /5/2/3/ |
|   5 |   4 |     /5/4/ |
|   6 |   7 |     /6/7/ |
|   7 |   6 |     /7/6/ |
源表将包含大约100000条记录


没有什么能帮到你。这项任务很不愉快——找到所有可能的联系。几乎交叉连接。最后还有更多的联系。

看起来我想出了一个与其他海报类似的答案。我的方法是插入现有的值对,然后插入每个值对的反面

展开值对列表后,可以横穿该表以查找所有值对

CREATE TABLE #Source
    ([ID1] int, [ID2] int);

INSERT INTO #Source 
(
    [ID1]
    ,[ID2]
) 
VALUES   
(1, 2)
,(2, 3)
,(4, 5)
,(2, 5)
,(6, 7)

INSERT INTO #Source 
(
    [ID1]
    ,[ID2]
) 
SELECT 
    [ID2]
    ,[ID1] 
FROM #Source

;WITH expanded AS
(
    SELECT DISTINCT 
        ID1 = s1.ID1
        ,ID2 = s1.ID2
    FROM #Source s1
    LEFT JOIN #Source s2 ON s1.ID2 = s2.ID1

    UNION

    SELECT DISTINCT 
        ID1 = s1.ID1
        ,ID2 = s2.ID2
    FROM #Source s1
    LEFT JOIN #Source s2 ON s1.ID2 = s2.ID1
    WHERE s1.ID1 <> s2.ID2

)
,recur AS
(
    SELECT DISTINCT 
        e1.ID1
        ,e1.ID2
    FROM expanded e1
    LEFT JOIN expanded e2 ON e1.ID2 = e2.ID1
    WHERE e1.ID1 <> e1.ID2

    UNION ALL

    SELECT DISTINCT 
        e1.ID1
        ,e2.ID2
    FROM expanded e1
    INNER JOIN expanded e2 ON e1.ID2 = e2.ID1
    WHERE e1.ID1 <> e2.ID2
)
SELECT DISTINCT 
    ID1, ID2 
FROM recur
ORDER BY ID1, ID2

DROP TABLE #Source 

你能提供一个预期产出的例子吗?我不清楚您所说的获取标识符之间具有完全依赖关系的表是什么意思。请用文本替换文本图片,并提供您目前拥有的代码。如果您必须使用它们,请确认它们是否巨大。图片已编辑。显示源表和预期输出。数据和表的图片通常没有帮助。为什么?谢谢但数据集将不同,源表将包含大约100000条记录。这个决定太粗糙了。好吧,至少分隔符是不同的。即使是提示也几乎是逐字逐句,这很有趣戈登,伊万谢谢你的回答!在我看来,这是解决问题的好办法!
CREATE TABLE #Source
    ([ID1] int, [ID2] int);

INSERT INTO #Source 
(
    [ID1]
    ,[ID2]
) 
VALUES   
(1, 2)
,(2, 3)
,(4, 5)
,(2, 5)
,(6, 7)

INSERT INTO #Source 
(
    [ID1]
    ,[ID2]
) 
SELECT 
    [ID2]
    ,[ID1] 
FROM #Source

;WITH expanded AS
(
    SELECT DISTINCT 
        ID1 = s1.ID1
        ,ID2 = s1.ID2
    FROM #Source s1
    LEFT JOIN #Source s2 ON s1.ID2 = s2.ID1

    UNION

    SELECT DISTINCT 
        ID1 = s1.ID1
        ,ID2 = s2.ID2
    FROM #Source s1
    LEFT JOIN #Source s2 ON s1.ID2 = s2.ID1
    WHERE s1.ID1 <> s2.ID2

)
,recur AS
(
    SELECT DISTINCT 
        e1.ID1
        ,e1.ID2
    FROM expanded e1
    LEFT JOIN expanded e2 ON e1.ID2 = e2.ID1
    WHERE e1.ID1 <> e1.ID2

    UNION ALL

    SELECT DISTINCT 
        e1.ID1
        ,e2.ID2
    FROM expanded e1
    INNER JOIN expanded e2 ON e1.ID2 = e2.ID1
    WHERE e1.ID1 <> e2.ID2
)
SELECT DISTINCT 
    ID1, ID2 
FROM recur
ORDER BY ID1, ID2

DROP TABLE #Source