查找所有匹配标识符的递归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