sql - 我应该如何识别每条记录可能有多个身份的重复项组?

标签 sql oracle

我有一个要尝试消除重复的组织列表。每个组织最多可以在三个不同领域拥有三个标识号。目前我可以使用的工具是 Oracle SQL 数据库和 SAP Data Services。

Name  |ID1     |ID2     |ID3
------|--------|--------|--------
Org1  |1       |<null>  |2        
Org2  |<null>  |1       |<null>  
Org3  |2       |<null>  |<null>    

所有这三个组织都应该能够被识别为一个组织。


第一种方法

解决这个问题的第一个方法是将其分解为组织和 ID 的有序列表。

Name  |ID        
------|-------
Org1  |1              
Org2  |1       
Org1  |2      
Org3  |2       

从那时起,我设法使用数据转换组合来创建仅重复 ID 的列表,其中涉及仅选择可能的 ID 列表、对它们进行排序、删除唯一 ID、为每个 ID 分配一个 ROW_ID(表示作为本示例中的一封信,即使它看起来多余)。

ID    |Duplicate_Group     
------|--------
1     |A              
2     |B   

但是如果我将其加入到我的数据中,它并不能解决我的问题。它只会导致进一步的重复。在我意识到我们的组织可以有多个 ID 之前,我最初接受了本类(class)作为我的解决方案:

Name  |ID1     |ID2     |ID3     |Duplicate_Group
------|--------|--------|--------|--------
Org1  |1       |<null>  |2       |A 
Org1  |1       |<null>  |2       |B 
Org2  |<null>  |1       |<null>  |A 
Org3  |2       |<null>  |<null>  |B   

新方法

我的下一个想法是类似地分配字母来区分我的组织之间的组,但是......循环数据。

Name  |ID      |Duplicate_Group
------|--------|--------
Org1  |1       |A 
Org1  |2       |B 
Org2  |1       |A 
Org3  |2       |B   

首先,按名称、ID 排序,我会检查名称或 ID 是否与前一行相同,然后采用该重复组作为您自己的组。

Name  |ID      |D_Grp1  |D_Grp2
------|--------|--------|--------
Org1  |1       |A       | 
Org1  |2       |B       |A
Org2  |1       |A       | 
Org3  |2       |B       | 

请注意,第二行中 Org1 的 D_Grp2 已更改。现在,我将把旧的 D_Grp1 合并到 D_Grp2 中,然后再做一次——按 ID 顺序,然后是名称;然后再次根据上一行更新组。

Name  |ID      |D_Grp2  |D_Grp3
------|--------|--------|--------
Org1  |1       |A       | 
Org2  |1       |A       | 
Org1  |2       |A       | 
Org3  |2       |B       |A

由于第四行的 ID 与上面相同,但具有不同的 D_Grp2,因此第四行将更新其 D_Grp3 以匹配。我的想法是,我会一遍又一遍地循环这个按 ID 和名称排序的过程,直到不再需要进行更改。我将使某种列或变量充当标志 - 在每次循环之后,如果标志没有勾选,我将假设所有内容都已合并。我将应用一个不同的并将其打回到原始表中。

Name  |ID1     |ID2     |ID3     |Duplicate_Group
------|--------|--------|--------|--------
Org1  |1       |<null>  |2       |A 
Org2  |<null>  |1       |<null>  |A 
Org3  |2       |<null>  |<null>  |A  

就范围而言,我有大约 60,000 个组织,因此循环并非不可能,但它让我感到恶心,需要很长时间,而且似乎无法设计更好的流程。我也不太确定我是否错过了任何边缘情况,即按名称和 ID 排序可能永远不会合并记录。


结论

那么StackOverflow,有没有更好的方法来识别这个表中的重复项?我可以接受任何答案,包括 SQL。请理解 SAP Data Services 的逻辑基本上是 SQL,但我不是直接编写自己的 SQL - 因此到目前为止我无法提供我的流程的 SQL 版本。

最佳答案

这绝对是一个迭代过程,因此需要递归查询。

一定是在寻找链式店。如果 ID 1 = 2、2 = 3、4 = 5、5 = 6、2 = 5,则所有这些 ID 都表示同一家公司。

这是我的算法:

  1. 查找所有对 1 = 2, 2 = 1, 2 = 3, ...
  2. 查找所有链(对于 ID 1:1=2=3、1=2=5,对于 ID 2:2=1、2=3、2=5 对于 ID 3:3=2=1、3= 2=5, ...) 并将调用 ID 作为链号赋予链中的所有 ID。 (因此 ID 3 的链号为 1(来自第一条链)、2(来自第四条链)、3(来自第六条和第七条链)。)
  3. 通过将每个 ID 与其最小链号相关联来构建组。 (因此,ID 3 的链号为 1;ID 3 属于组“chain=1”。)具有相同最小链号的所有 ID 代表同一家公司。

这是查询:

with pairs as
(
  select id1 as id, id2 as other from mytable where id1 <> id2
  union all
  select id1 as id, id3 as other from mytable where id1 <> id3
  union all
  select id2 as id, id1 as other from mytable where id2 <> id1
  union all
  select id2 as id, id3 as other from mytable where id2 <> id3
  union all
  select id3 as id, id1 as other from mytable where id3 <> id1
  union all
  select id3 as id, id2 as other from mytable where id3 <> id2
)
, chains(chain, id) as
(
  select id as chain, id from pairs
  union all
  select c.chain, p.other as id
  from chains c
  join pairs p on p.id = c.id
)
cycle chain, id set cycle to 1 default 0
, groups as
(
  select id, min(chain) as grp 
  from chains 
  group by id
)
select distinct g.grp, m.*
from groups g
join mytable m on g.id in (m.id1, m.id2, m.id3)
order by g.grp, m.name;

当您有很多表示同一家公司的 ID(即要评估很多链)时,此查询可能会非常慢。如果这种情况发生的次数很少(看起来可能性更大),那么查询将会非常快。试试吧:-)

关于sql - 我应该如何识别每条记录可能有多个身份的重复项组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43625826/

相关文章:

sql - 在 Azure Synapse 中使用 SQL 声明变量时出错

Mysql 匹配 "Same"邮件

php - 如何将两个数组组合成一个循环?

sql - Oracle DB 表中的第二大值

oracle - 查找每组其他行的最大值

mysql - 加速大表上的简单 UPDATE 查询

MySQL 事件未触发

sql - 调用 CURDATE() 时出错

sql - 函数 main() 中的编译器错误 E2451 undefined symbol 'EXEC'

java - 多线程和集群环境中的自定义序列生成