元組

2017-06-13 57 views
6

的SQL重複數據刪除名單我有ID的兩列,像這樣的表:元組

╔════════╦══════╗ 
║ Master ║ Dupe ║ 
╠════════╬══════╣ 
║ 2  ║ 7 ║ 
║ 3  ║ 6 ║ 
║ 6  ║ 7 ║ 
║ 20  ║ 25 ║ 
║ 75  ║ 25 ║ 
╚════════╩══════╝ 

每一行代表一個SQL表兩行被認爲是相互重複的ID。

此表格可以包含數千個條目,但不保證除Master列以外的數據按升序排列,如圖所示。任一列都可以包含與另一列相同的ID,可能會針對不同或相同的合作伙伴ID。再次 - 沒有保證。

從這張表格中,我想得到一個Master及其所有可能的模糊的索引。如下圖所示。

期望的結果:

  1. 最低ID應保持作爲主
  2. 一欺騙的所有後續愚弄應該映射回到相同的(最低ID)主

針對上述情況,期望的輸出將如下所示(但列不必分類):

╔════════╦══════╗ 
║ Master ║ Dupe ║ 
╠════════╬══════╣ 
║ 2  ║ 3 ║ 
║ 2  ║ 6 ║ 
║ 2  ║ 7 ║ 
║ 20  ║ 25 ║ 
║ 20  ║ 75 ║ 
╚════════╩══════╝ 

我發現很難解釋這個問題,所以我的谷歌搜索沒有返回太多。我在想,必須有一個算法來遍歷這樣的元組列表並發現重複。

任何幫助表示讚賞!

編輯:我修改了示例表以更好地解釋它們的內容可能看起來像什麼。

的一些注意事項需要考慮,

  • 沒有一個鏈條的保證。它可能都是一個大的連鎖店,很多小的連鎖店或者根本沒有。
  • 沒有保證所有配對出現在相反的順序中某處表

從我所看到的,這個問題看起來是遞歸的,我覺得LukStorms是在正確的軌道上,但我可以」噸相當數字它

答案:雖然下面的兩個解決方案從@artm和@LukStorms似乎工作,我發現後者是一個更簡潔和可讀。謝謝你們倆!對一個棘手問題的神奇幫助。我只希望我能給你答案

+3

你能更好地解釋你的邏輯是什麼? 2和3之間的關係的性質是什麼,因爲它出現在結果集中,與原始表格有什麼不同? –

+0

當然,3和6是模糊,6和7是模糊,7和2是模糊。保持最低的ID(2),ID的3,6和7都是2的騙局。 –

回答

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; 
+0

我喜歡RCTE所在的位置,但是這個過程似乎假設整個事物是一個鏈,而且它是循環的,因爲它與原始對相反。 如果你在底部拿出'7,2'對,它不再起作用,而結果應該是一樣的。 請看看修改後的例子,如果你願意的話:) –

+1

@SeanMissingham事實上,這個假設是基於以前的測試數據。雖然不會將其視爲「單鏈」,但更像是獲得分支機構。答案已更新。 – LukStorms

4

試試這個。用CTE從表中獲取主表的最小值,並交叉連接表中的所有其他值。

;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 
+0

這假定它是全部鏈條,請參閱我的編輯 –

+1

@SeanMissingham查看更新 – artm

+2

@artm您可能想要查看那些row_number()的順序。當在第一個CTE中使用表時,那麼'(select 1)'不會給出正確的順序,所以結果可能會不同。 – LukStorms

1

晚會到了派對,但你似乎想要找到分離的集合。 如果你關心效率,這裏有一個非常快的算法,它涉及到數據結構UnionFind。這似乎是比甚至更快的排序...

谷歌搜索SQL實現,我是鉛there