php - 在这种(稍微)复杂的 MySQL 数据库情况下,如何删除重复行?

标签 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 为每个人保存了多个值。这就是表的结构(table2 中有大约一百万行,所以我现在不想更改结构)。

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

编辑:我确信我可以删除每个表的 ID 字段,但就我而言,它只是......在那里。

最佳答案

通过第一个澄清和行间的一些阅读,我们可以猜测,在表 1 中仅保留给定“唯一 ID 代码”的第一个或最后一个条目就足够了,其中第一个或最后一个表示最旧或最新入口。除了 MAX 与 MIN 之外,查询是相同的。我假设“日期”列包含足够精细(1 秒或更小)的粒度,您不会在一个时间段内两次获得相同的唯一 ID 代码;如果“日期”列实际上只包含 DATE(年、月、日)值,则不太可能出现这种情况,但如果您有 TIMESTAMP(3),则可能是这种情况,并且很可能是 TIMESTAMP 的情况。

与 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。

使用生产数据库的副本进行实验。

关于php - 在这种(稍微)复杂的 MySQL 数据库情况下,如何删除重复行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4772586/

相关文章:

java - hibernate中M-M关系中的记录顺序不正确

mysql - 查询在包含信息的列上返回 null

sql - 更新数据库失败,因为数据库是只读的

node.js - MongoDB:将多个文档插入具有唯一索引的集合中,即使有些文档违反了索引

php - 将3列的总和合并到php mysql中的另一列

MYSQL 双连接表和不准确的计数/求和

php - CodeIgniter 其中值 IN (Field1,Field2)

php - 需要获取10000个类别的最近类别更改(添加后、修改后)日期

找不到 PHP 类 'Ds\Map'

php - Magento - PayPal 未重定向到移动网站