【问题标题】:Oracle, how to remove almost same rows from the tableOracle,如何从表中删除几乎相同的行
【发布时间】:2016-10-13 23:23:18
【问题描述】:

多年来,由于拼写错误,我们的数据表中添加了一些重复项。例如,有人拼错了名字,而不是 O'leary 写了 Oleary。我们的系统认为它是一个完全不同的名字并且不会抱怨它,但是在大多数情况下它的同一个联系人输入了两次(我没有构建这个系统)。

现在我想做的是删除所有这些重复项,但是我很难构建一个查询来显示它们。我确实对 UTL_MATCH 进行了试验,并编写了一个查询,如果我提供名称,它将返回所有相似的名称。

select first_name from customers 
where UTL_MATCH.edit_distance_similarity(first_name,'Oleary') > 60
order by first_name;

但是,我想构建一个查询,该查询将自动返回所有可能的重复项,而无需提供名称。谁能指出我正确的方向吗?

【问题讨论】:

  • 问题陈述存在逻辑不一致。可以有三个名字,分别称它们为 fn1、fn2、fn3,其中 fn1 和 fn3 都与 fn2“足够相似”,但彼此不“足够相似”。在这种情况下,您可以保留 fn2 并删除其他两个,或者您可以保留 fn1 和 fn3 但删除中间的一个。然后 fn3 可能与 fn4 相似,但 fn4 与 fn1 的“足够”相似,等等。在考虑任何解决方案之前,您需要一个更明确的问题陈述。
  • 对不起,mathguy,也许我们的智商水平之间的差异妨碍了我(我不明白你刚才说的是什么),但是我尽我所能尽可能简单地解释我的问题,我在下面看到一些几乎回答了我的查询的答案,所以看来我并没有完全失败。但感谢您的意见。
  • 举例说明:同名的三个不同版本,拼写不同(无论出于何种原因),但同一个人。名字是 JADA、JEDA 或 GEDA。 “相似”是多少个共同的字母。 JADA 到 JEDA 是 75%(它们相似度超过 60%),JEDA 和 GEDA 也有 75%,但 JADA 和 GEDA 只有 50% 相似。如果您使用查询并在 distance_similarity 中使用“JEDA”,则将选择其他两个名称。但是如果你使用'JADA'进行比较,'GEDA'将不会被选中。所以“所有重复”的概念没有很好的定义。
  • 同理,如果应用“我朋友的朋友就是我的朋友”,你可能会有这样的情况:ABC类似于DBC,类似于DEC,即类似于 DEF。这是否意味着 ABC 类似于 DEF?
  • 哈!现在我明白了:)谢谢!我认为如果要实现您的想法,下面所述的查询会变得更有效率,但也许这次不需要,因为我可以完成工作,我只需要做一次,所以速度并不那么重要.

标签: sql oracle plsql oracle11gr2


【解决方案1】:

这样的事情在技术上是可行的。

select c1.first_name, c2.first_name
  from customers c1
       cross join customers c2
 where utl_match.edit_distance_similarity( c1.first_name, c2.first_name ) > 60
 order by c1.first_name

但是,除非您的 customers 表恰好非常(非常)小,否则它会非常慢,因为您将 customers 表中的每一行与表中的每一行进行比较(以及您的编辑距离相似性截止非常低)。为了加快速度,您可能必须对您的数据做出假设,或者做一些其他可以作为初步过滤的事情。例如,如果您假设任何重复项都以相同的第一个字符或相同的前几个字符开头而忽略标点符号,那么您可以大大减少需要匹配的对数,但有可能会错过“Kustin”可能是第一个字符不同的“贾斯汀”的错字重复。要求c2.customer_id > c1.customer_id 将是另一个合理的过滤器,可以考虑假设您不需要重复每一对(即“Kustin/Justin”行可以在没有等效的“Justin/Kustin”行的情况下存在)。

【讨论】:

  • 感谢您的回答!我尝试了一种非常相似的方法,不得不在 5 分钟后取消我的查询,它仍在运行,我认为我的代码有问题。有什么办法可以提高速度?
  • @K.I - 就像我说的,将表中的每一行与表中的每一行进行比较会非常慢。您需要根据对数据的一些了解,想出一些合理的方法来限制您需要考虑的组合。我提到了一些对你来说可能或可能不合理的可能性。不幸的是,很难猜测什么是对您的数据合理的启发式方法。例如,您的客户可能有地址信息,而您只能比较相同邮政编码的客户。或者你可以让它在一夜之间运行几个小时。
【解决方案2】:

您可以将其用于join

select c1.first_name, c2.first_name
from customers c1 join
     customers c2
     on UTL_MATCH.edit_distance(c1.first_name, c2.first_name) <= 3
order by c1.first_name;

注意事项:

  • 比起edit_distance_similarity(),我更喜欢edit_distance(),因为我了解单位。
  • 连接会很慢,很慢,很慢,所以希望您没有太多行。
  • 可能会有很多错误匹配,所以要小心。

【讨论】:

  • 我只想在连接子句中添加一个and c1.first_name &lt; c2.first_name 以避免无用的重复(和完全匹配)
  • 感谢您的回答!我尝试了一种非常相似的方法,不得不在 5 分钟后取消我的查询,它仍在运行,我认为我的代码有问题。有什么办法可以提高速度?
  • @K.I 。 . .从表的一小部分开始,例如以“A”开头的名称,看看情况如何。
猜你喜欢
  • 1970-01-01
  • 2020-10-01
  • 2019-04-07
  • 2014-06-02
  • 1970-01-01
  • 2011-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多