我有一个包含两列ID的表,如下所示:
╔════════╦══════╗
║ Master ║ Dupe ║
╠════════╬══════╣
║ 2 ║ 7 ║
║ 3 ║ 6 ║
║ 6 ║ 7 ║
║ 20 ║ 25 ║
║ 75 ║ 25 ║
╚════════╩══════╝
每行表示sql表中两行的ID,这两行被认为是彼此重复的。
此表可以包含数千个条目,但不保证Master
列以外的数据按照图示的升序排序。任何一列都可以包含与另一列相同的ID,可能针对不同或相同的合作伙伴ID。再次 - 没有保证。
从这张表中我想获得Master的索引及其所有可能的欺骗。如下图所示。
期望的结果:
对于上面的内容,所需的输出看起来像是这样(但是列不必排序):
╔════════╦══════╗
║ Master ║ Dupe ║
╠════════╬══════╣
║ 2 ║ 3 ║
║ 2 ║ 6 ║
║ 2 ║ 7 ║
║ 20 ║ 25 ║
║ 20 ║ 75 ║
╚════════╩══════╝
我发现很难解释这个问题所以我的谷歌搜索没有太多回复。我认为必须有一个算法来迭代这样的元组列表并发现重复。
任何帮助表示赞赏!
编辑:我修改了示例表,以更好地解释其内容可能是什么样的。
需要考虑的一些注意事项,
从我所看到的,问题看起来是递归的,我认为LukStorms是在正确的轨道但我无法弄明白
回答:虽然@artm和@LukStorms下面的两个解决方案似乎都有效,但我发现后者更简洁,更易读。谢谢你们俩!一个棘手问题的神奇帮助。我只希望我能给你答案
答案 0 :(得分:4)
试试这个。使用CTE从表中获取master的最小值并交叉连接到表中的所有其他值。
;WITH minmaster as (select MIN(MASTER) master
FROM myTable)
select distinct m.master
, i.dupe
from minmaster m
cross join (select dupe dupe from myTable union all select master from myTable) i
WHERE i.dupe <> m.master
<强>更新强>
使用更多行进行编辑后,下面有效,但我不确定它是否是最佳解决方案。逻辑从第一个主设备开始(因为数据按主数据排序),如果第一列不等于当前主设备的第二列存在欺骗,则采用相同的主设备,否则采用下一个主设备。很难解释,其他人可能会找到一个更容易的解决方案。
;WITH myTable AS
(SELECT 2 MASTER, 7 dupe
UNION all SELECT 3, 6
UNION all SELECT 6, 7
UNION all SELECT 20, 25
UNION all SELECT 75, 25
UNION all SELECT 100, 125
UNION all SELECT 150, 300
UNION all SELECT 180, 300
)
, cte AS
(
SELECT m.master L, m.dupe R, ROW_NUMBER() OVER (ORDER BY master) rnkC
FROM myTable m
)
, cte2 AS
(
SELECT m.master L, m.dupe R, ROW_NUMBER() OVER (ORDER BY master) rnkC2
FROM myTable m
)
, cteCur AS
(
SELECT TOP 1 cte.l, cte.R, cte.rnkC
FROM cte
UNION ALL
SELECT
CASE WHEN cteCur.r IN (SELECT dupe
FROM myTable
WHERE MASTER <> cteCur.L AND dupe = cteCur.R)
THEN cteCur.L
ELSE (SELECT cte2.L
FROM cte2
WHERE cte2.rnkC2 = cteCur.rnkC + 1)
END
, CASE WHEN cteCur.r IN (SELECT dupe
FROM myTable
WHERE MASTER <> cteCur.L AND dupe = cteCur.R)
THEN (SELECT cte2.L
FROM cte2
WHERE cte2.R = cteCur.R AND cte2.L <> cteCur.L)
ELSE (SELECT cte2.R
FROM cte2
WHERE cte2.rnkC2 = cteCur.rnkC + 1)
END
, cteCur.rnkC + 1
FROM cteCur
WHERE cteCur.L IS NOT NULL
)
SELECT cteCur.L Master
, cteCur.R Dupe
FROM cteCur
WHERE L IS NOT NULL
ORDER BY L, R
答案 1 :(得分:2)
这是一个使用递归CTE连接这些重复项的示例。
但为了确保副本全部在两个方向上,使用了DUPES CTE。
declare @DuplicateTest table (Master int, Dupe int);
insert into @DuplicateTest (Master, Dupe) values
(3,6),(6,7),(2,7),
(20,25),(75,25);
;with DUPES as
(
select distinct Master as Dupe1, Dupe as Dupe2 from @DuplicateTest
union
select distinct Dupe, Master from @DuplicateTest
)
,RCTE as
(
select Dupe1 as Base, 0 as Level, Dupe1, Dupe2
from DUPES
union all
select r.Base, (r.Level + 1), d.Dupe1, d.Dupe2
from RCTE r
join DUPES d on (r.Dupe2 = d.Dupe1
and r.Dupe1 != d.Dupe2 -- don't loop on the reverse
and r.Base != d.Dupe2 -- don't repeat what we started from
and r.Level < 100) -- if the level gets to big it's most likely a loop
)
select min(Dupe2) as Master, Base as Dupe
from RCTE
group by Base
having Base > min(Dupe2)
order by Base;
答案 2 :(得分:1)