我有一张包含重复信息的表:Id,姓名,姓氏,出生,PersonalKey,个人信息,方向,来源。
来源告诉我信息的来源。
重复的信息具有唯一ID,我需要删除欺骗信息。 但是,我优先考虑一些源信息,我需要保留这些信息,另一个信息将被删除。
其他的事情是,另一个Source信息有一些信息,我想要留下的信息没有,所以我需要将PersonalKey重新填充到剩下的那个并删除重复的那个。
表名为Pruebas
---Id, Name, Firstname, Lastname, Birth, RFC, Source, PersonalKey---
---2,Juan,Garcia,Escobeddo,1983-08-04,GAED87393, DRV484930, 34233--
---3,Juan,Garcia,Escobedo,1987-08-04,GAED87393, FIN484930, --
---4,Juan,Garcia,Escobedo,1987-08-04,GAED87393, SA484930, --
如你所见:
提前致谢。
答案 0 :(得分:3)
我会在这个查询上运行一个游标(使用MySQL SP编程语言,Java,Python,.NET):
select Name, Firstname, Lastname, count(1)
from Pruebas
group by Name, Firstname, Lastname
having count(1) > 1
然后,在光标返回的行上,只需执行以下操作:检查FIN%实例,检查PersonalKey的存在,并相应地更新。
对于光标上的每一行,您可以使用以下命令打开另一个光标:
select *
from Pruebas
where Name = the_Name
and Firstname = the_Firstname
and Lastname = the_Lastname
现在,您将拥有一个内部光标,其中包含您要修改的所有行。如果它是您需要的,请保留它并使用您提到的KEY值更新它。否则,删除它。
在Oracle中,您可以在一个查询中完成您想要的任务,但我不认为您将获得与此方法相同的性能。
希望它有所帮助。
答案 1 :(得分:3)
我能想到的最直接的解决方案是将PersonalKey
复制到其他重复行,然后删除所有与'FIN%'
不匹配的行。
UPDATE Pruebas p1 JOIN Pruebas p2
ON (SOUNDEX(CONCAT(p1.Name, p2.Firstname, p3.Lastname))
= SOUNDEX(CONCAT(p2.Name, p2.Firstname, p2.Lastname)))
SET p1.PersonalKey = p2.PersonalKey
WHERE p2.PersonalKey IS NOT NULL;
DELETE FROM Pruebas WHERE Source NOT LIKE 'FIN%';
我正在使用SOUNDEX()
显示联接的近似匹配表达式。
我从其他评论中看到,你已经离开了很多变化和不确定性。在这种情况下,没有办法自动清理和重复数据删除 - 或者至少自动清理将比手动执行更复杂,更难做到。
请注意,查询需要花费很多时间:是的,实际上预计不会有效。 JOIN表达式不是 sargable - 也就是说,它无法利用索引。您可以通过添加额外的列来物理存储名称,名字,姓氏的SOUNDEX()
值,从而提高效率。然后在该列上创建索引。
但SOUNDEX()
无法保证找到所有可能的拼写错误。您正面临无法完全自动执行的数据清理任务。 任何数据清理解决方案都需要手动操作。
答案 2 :(得分:2)
我会做这样的事情:
创建表Pruebas_new
SELECT * FROM Pruebas
GROUP BY名称,名字,姓氏
拥有像'FIN%'的来源;
如果您需要更快,可以使用临时表重写并覆盖原始表中的内容,但这样可以以最简单的方式获取所需的数据。
答案 3 :(得分:1)
很抱歉答案延迟了。过去几天我有点忙。
以下是基于以下假设的答案:
1)您将通过其他一些机制清理名称拼写问题(您提到过要在原始问题的评论中使用正则表达式清理它)。
2)可以使用名字,姓氏和出生来识别DUP集(您在对原始问题的评论中提到了这一点。)
3)Firstname,Lastname和Birth不能为NULL。
4)你不能在DUP集中拥有多条FIN记录(你在对原始问题的评论中提到过这一点)。
如果上述任何假设无效,则必须修改我的答案。
以下是要采取的步骤:
1)更新所有FIN记录以通过非FIN记录复制PersonalKey:
UPDATE Pruebas p1
INNER JOIN Pruebas p2
ON p1.Firstname = p2.Firstname
AND p1.Lastname = p2.Lastname
AND p1.Birth = p2.Birth
SET p1.PersonalKey = p2.PersonalKey
WHERE p1.Source like 'FIN%'
AND p1.PersonalKey is null
AND p2.PersonalKey is not null;
2)删除我们有FIN记录的所有非FIN记录:
DELETE p2
FROM Pruebas p1
INNER JOIN Pruebas p2
ON p1.Firstname = p2.Firstname
AND p1.Lastname = p2.Lastname
AND p1.Birth = p2.Birth
WHERE p1.Source like 'FIN%'
AND p2.Source not like 'FIN%';
此时所有带有FIN记录的DUP都已清除,因此只剩下FIN记录。
3)如果我们决定继续使用所有其他病例的DRV记录。我们需要将PersonalKey从另一条记录复制到DRV记录中:
UPDATE Pruebas p1
INNER JOIN Pruebas p2
ON p1.Firstname = p2.Firstname
AND p1.Lastname = p2.Lastname
AND p1.Birth = p2.Birth
SET p1.PersonalKey = p2.PersonalKey
WHERE p1.Source like 'DRV%'
AND p1.PersonalKey is null
AND p2.PersonalKey is not null;
4)删除我们拥有DRV记录的所有非DRV记录:
DELETE p2
FROM Pruebas p1
INNER JOIN Pruebas p2
ON p1.Firstname = p2.Firstname
AND p1.Lastname = p2.Lastname
AND p1.Birth = p2.Birth
WHERE p1.Source like 'DRV%'
AND p2.Source not like 'DRV%';
此时,所有具有DRV记录的DUP都已清除,因此只剩下DRV记录。
如果唯一的其他记录类型是SA记录,则不应再有DUP,我们就完成了。
5)如果我们想要选择填写了最多信息的记录,或者如果我们完成了3和4并且还有多个记录类型仍然留下导致DUP。我们需要将具有DUP集的任何记录中的PersonalKey复制到任何没有所有非FIN记录的记录中:
UPDATE Pruebas p1
INNER JOIN Pruebas p2
ON p1.Firstname = p2.Firstname
AND p1.Lastname = p2.Lastname
AND p1.Birth = p2.Birth
SET p1.PersonalKey = p2.PersonalKey
WHERE p1.Source not like 'FIN%'
AND p1.PersonalKey is null
AND p2.PersonalKey is not null;
6)删除除信息最多的记录以外的所有记录(由info_score计算列定义):
DELETE p5
FROM Pruebas p5
INNER JOIN (SELECT p3.Firstname
, p3.Lastname
, p3.Birth
, MIN(p3.Id) AS min_id
FROM Pruebas p3
INNER JOIN (SELECT p1.Firstname
, p1.Lastname
, p1.Birth
, count(*) AS c
, MAX((p1.Name is not null) + (p1.RFC is not null) + (p1.Source is not null) + (p1.PersonalKey is not null)) AS info_score
FROM Pruebas p1
GROUP BY p1.Firstname
, p1.Lastname
, p1.Birth
HAVING count(*) > 1) p2
ON p3.Firstname = p2.Firstname
AND p3.Lastname = p2.Lastname
AND p3.Birth = p2.Birth
AND ((p3.Name is not null) + (p3.RFC is not null) + (p3.Source is not null) + (p3.PersonalKey is not null)) = p2.info_score
GROUP BY p3.Firstname
, p3.Lastname
, p3.Birth) p4
ON p4.Firstname = p5.Firstname
AND p4.Lastname = p5.Lastname
AND p4.Birth = p5.Birth
AND p4.min_id <> p5.Id;
此时所有DUP都已折叠,如果可用,则保存PersonalKey,如果存在则保存FIN记录,否则保存DRV记录或信息最多的记录。
如果您对上述任何问题有任何疑问,请与我们联系。
希望它有所帮助,
-Dipin