如何删除此(轻度)复杂的MySQL数据库情况中的重复行?

时间:2011-01-23 06:17:49

标签: php mysql database greatest-n-per-group

确定。请耐心等待我解释。

我有一个通过网站上的表单收集的联系信息数据库。显然,人们不小心按下提交不止一次(或故意,但修复是一个不同的问题)所以这个数据库中有很多重复的行。

因此,table1保存联系信息:

ID  |  date  |  unique ID code  |  first name, blah blah
1      stuff    20110101ba78b      joe

table2保存由唯一ID代码字段连接的相关数据,如下所示:

ID  |  data  |  unique ID code
1      a        20110101ba78b
2      b        20110101ba78b

因此,table2为每个人保留多个值。这就是表的结构(表2中有大约一百万行,所以我现在不想改变结构。)

所以我的困境是这样的:我知道创建临时表和SELECT DISTINCT(所有字段)很容易,但我想保留至少1个重复行的唯一ID字段。如果我保留唯一ID字段,它对每一行都是唯一的,即使其他数据完全相同,因此SELECT DISTINCT(所有字段)将不起作用,它将保留每一行。希望我彻底解释了这一点。如果需要,请向我询问更多信息。

编辑:我确信我可以摆脱每张桌子的ID字段,但就我而言,它只是......它就在那里。

2 个答案:

答案 0 :(得分:1)

通过第一次澄清和线条之间的一点阅读,我们可以猜测,只保留表1中给定“唯一ID代码”的第一个或最后一个条目,其中第一个或最后一个表示最旧或最新条目。除了MAX和MIN之外,查询是相同的。我假设“日期”列包含足够精细(1秒或更小)的粒度,在时间量上你没有得到两次相同的唯一ID码;如果“日期”列实际上只包含DATE(年,月,日)值,则情况不太可能如此,但如果您有TIMESTAMP(3)可能就是这种情况,TIMESTAMP可能就是这种情况。 / p>

与SQL一样,分阶段构建查询,很好,轻柔。

查找具有多个条目的每个唯一ID代码的最新条目

SELECT Unique_ID_Code, MAX(date) AS Newest
  FROM Table1
 GROUP BY Unique_ID_Code
HAVING COUNT(*) > 1

查找与最新条目

匹配的唯一ID代码的详细信息
SELECT T1.*
  FROM Table1 AS T1
  JOIN (SELECT Unique_ID_Code, MAX(date) AS Newest
          FROM Table1
         GROUP BY Unique_ID_Code
        HAVING COUNT(*) > 1
       ) AS M
    ON M.Unique_ID_Code = T1.Unique_ID_Code AND M.Newest = T1.Date

现在是棘手的东西

您接下来要做的事情取决于您对DBMS中的事务支持的信任程度以及Table1的大小,以及您是否对外键具有ON DELETE CASCADE约束,以及......

您可以使用上面第二个查询选择的行创建一个临时表(我相信MySQL语法;其他DBMS对此使用不同的表示法。)

CREATE TEMPORARY TABLE KeepTheseRows
    SELECT T1.*
      FROM Table1 AS T1
      JOIN (SELECT Unique_ID_Code, MAX(date) AS Newest
              FROM Table1
             GROUP BY Unique_ID_Code
            HAVING COUNT(*) > 1
           ) AS M
        ON M.Unique_ID_Code = T1.Unique_ID_Code AND M.Newest = T1.Date;

然后删除Table1中与重复的唯一ID代码匹配的所有行:

DELETE FROM Table1
    WHERE Unique_ID_Code IN (SELECT Unique_ID_Code FROM KeepTheseRows);

然后恢复要保留的行:

INSERT INTO Table
    SELECT * FROM KeepTheseRows;

在发生这种情况时,您可能需要推迟约束检查,或者在发生这种情况时您可能需要删除外键约束。此操作发生时您需要担心活动;如果人们在运行时没有在Table1中插入行,那将是最好的。如果他们在您运行时修改表,您可能会发现必须多次进行处理。您应该尽快向Table1.Unique_ID_Code添加一个唯一约束,这样您就不会再次陷入混乱。 (并且不要忘记重新启用任何延迟约束或重新创建和删除外键。)

可能有其他等效方法可以做到这一点;除了临时表表示法之外,它仅依赖于标准(SQL-92)SQL。

尝试使用生产数据库的副本。

答案 1 :(得分:0)

这将更新表2以使用相同联系信息的最低唯一ID号:

UPDATE Table2
SET Table2.uniqueID = (
    SELECT T1.UniqueID
    FROM Table1 T1, Table1 T2
    WHERE T1.unique ID < T2.unique ID
    AND T1.firstname = T2.firstname
    AND T1.date = T2.date
    AND T1.blah, blah = T2.blah, blah
) 
WHERE Table2.uniqueID = (
    Select T1.UniqueID
    from Table1 T1, CopyOfTable1 T2
    where T1.firstname = T2.firstname
    and T1.date = T2.date
    and T1.blah, blah = T2.blah, blah
);

这将删除除ONE之外的所有(具有最低的uniqueID)重复的联系信息记录:

delete T1
from Table1 T1, CopyOfTable1 T2
where T1.unique ID > T2.unique ID
and T1.firstname = T2.firstname
and T1.date = T2.date
and T1.blah, blah = T2.blah, blah