MySQL重复 - 如何指定两个记录实际上不重复的时间?

时间:2010-09-18 05:44:31

标签: sql mysql duplicates

我有一个有趣的问题,我的逻辑不能胜任这个任务。

我们有一个表,有时会产生重复记录(出于过程原因,这是不可避免的)。请看以下示例:

id  FirstName  LastName  PhoneNumber   email
--  ---------  --------  ------------  --------------
 1  John       Doe       123-555-1234  jdoe@gmail.com
 2  Jane       Smith     123-555-1111  jsmith@foo.com
 3  John       Doe       123-555-4321  jdoe@yahoo.com
 4  Bob        Jones     123-555-5555  bob@bar.com
 5  John       Doe       123-555-0000  jdoe@hotmail.com
 6  Mike       Roberts   123-555-9999  roberts@baz.com
 7  John       Doe       123-555-1717  wally@domain.com

我们通过这种方式找到重复的内容:

SELECT c1.* 
FROM `clients` c1
INNER JOIN (
    SELECT `FirstName`, `LastName`, COUNT(*)
    FROM `clients`
    GROUP BY `FirstName`, `LastName`
    HAVING COUNT(*) > 1
) AS c2
ON c1.`FirstName` = c2.`FirstName`
AND c1.`LastName` = c2.`LastName`

这将生成以下重复列表:

id  FirstName  LastName  PhoneNumber   email
--  ---------  --------  ------------  --------------
 1  John       Doe       123-555-1234  jdoe@gmail.com
 3  John       Doe       123-555-4321  jdoe@yahoo.com
 5  John       Doe       123-555-0000  jdoe@hotmail.com
 7  John       Doe       123-555-1717  wally@domain.com

如您所见,基于FirstNameLastName,所有记录都是重复的。

此时,我们实际上打电话给客户以清除可能的重复项。

在这样做之后,我们学习(例如)记录1和3是真实的重复,但记录5和7实际上是两个不同的人。

因此,我们将记录1和3中任何无关链接的数据合并到记录1中,删除记录3,并单独留下记录5和7。

现在出现了问题:

下次我们重新运行“重复”查询时,它将包含以下行:

id  FirstName  LastName  PhoneNumber   email
--  ---------  --------  ------------  --------------
 1  John       Doe       123-555-4321  jdoe@gmail.com
 5  John       Doe       123-555-0000  jdoe@hotmail.com
 7  John       Doe       123-555-1717  wally@domain.com

它们似乎都是重复的,即使我们之前已经认识到它们不是。

您如何确定这些记录不重复?

我的第一个虽然建立一个查找表来识别哪些记录不是彼此重复的(例如,{1,5},{1,7},{5,7}),但我不知道如何构建一个能够使用这些数据的查询。

此外,如果显示另一个重复记录,则可能是1,5或7的副本,因此我们需要将它们全部显示在重复列表中,以便客户服务人员可以呼叫该人员。新记录,以找出他可能是重复的记录。

我试图理解这一点,我已经达到了极限。那里有哪些才华横溢的天才会对此有所了解?

2 个答案:

答案 0 :(得分:1)

有趣的问题。这是我对它的抨击。

如果我们从略微不同的角度处理问题怎么样呢。

考虑到系统一开始是干净的,即系统中当前所有记录都是使用唯一的第一个和最后一个名字组合,或者相同的第一个和最后一个名称已被手动确认为不同的人。

在系统中输入新用户时,我们会进行额外检查。可以实现为INSERT触发器,也可以仅在成功完成插入后调用另一个过程。

  1. 此触发器/过程匹配 FIRST + LAST名称组合 所有现有的“已插入”记录 表中的记录。
  2. 对于所有匹配的First + Last名称,它将在匹配表(新表)中使用NewUserID,ExistingMatchingRecordsUserID
  3. 创建一个条目

    从SQL的角度来看,

    TABLE MatchingTable
    COLUMNS 1. NewUserID 2. ExistingUserID
    Constraint : Logical PK = NewUserID + ExistingMatchingRecordsUserID
    
    INSERT INTO MATCHINGTABLE VALUES ('NewUserId', userId)
    SELECT userId FROM User  u where u.firstName = 'John' and u.LastName = 'Doe'
    

    MatchingTable中的所有条目都需要解析。

    当管理员登录系统时,管理员会看到MatchingTable中所有条目的列表

    例如:新用户John Doe - (ID 345) - 3个潜在匹配John Doe - ID 123 ID 231 / ID 256

    管理员将根据123/231和256中的数据检查345的数据,并手动确认是否重复ANY / None 如果Duplicate,则从用户表中删除345(软/硬删除 - 适合您的任何内容) 如果不是,ID 354的条目只是从MatchingTable中删除(我会在这里使用硬删除,因为这就像一个事务临时表,但一切都很好)。

    此外,当从MatchingTable中删除ID 354的条目时,将自动删除MatchingTable中ExistingMatchingRecordsUserID = 354的所有其他条目,以确保不需要对已经验证的数据进行不必要的手动验证。

    同样,这可能是一个潜在的DELETE触发/ Just逻辑另外在DELETE of MatchingTable上执行。实施受到优先考虑。

答案 1 :(得分:0)

以每行向表格添加单个字节为代价,您可以添加manually_verified BOOL列,默认值为FALSE。如果您手动验证了数据,请将其设置为TRUE。然后,您只需查询manually_verified = FALSE

的位置

它简单,有效,并且与业务流程中实际发生的事情相匹配:您手动验证数据。

如果您想更进一步,可能需要在验证行时进行存储并验证谁。由于存储在主表中可能很烦人,因此您当然可以将其存储在单独的表中,并在验证数据中存储LEFT JOIN。您甚至可以创建一个视图来重新创建单个主表的外观。

要解决添加新重复的问题:您将针对整个数据集检查未经验证的数据。这意味着您的主表c1的条件为manually_verified = FALSE,但您的INNER JOIN ed表c2却没有。这样,未经验证的数据仍将找到所有可能的重复匹配:

SELECT * FROM table t1
INNER JOIN table t2 ON t1.name = t2.name AND t1.id <> t2.id
WHERE t1.manually_verified = FALSE

重复项的可能匹配项将在联接表中。