【问题标题】:How to identify and delete duplicate rows, except for most recent如何识别和删除重复行,除了最近的
【发布时间】:2016-06-21 19:40:15
【问题描述】:

我在 HeidiSQL 中工作,我正在尝试弄清楚如何删除除最新行之外的所有重复行。 “重复项”之间存在一些细微差别,但只要有四个以上的特定值相同(即 UserID、ContactID、SMSID 和 EventID),则该行被视为重复项。我需要根据最近的行(由 CreatedDate 标识)删除这些。

以下查询标识这些行:

SELECT a.UserID, a.ContactID, a.SMSID, a.EventID, CreatedDate
FROM WhenToText a 
JOIN (SELECT UserID, ContactID, SMSID, EventID
       FROM WhenToText 
       GROUP BY UserID, ContactID, SMSID, EventID
       HAVING COUNT(*) > 1 ) b
ON a.UserID = b.UserID
AND a.ContactID = b.ContactID
AND a.SMSID = b.SMSID
AND a.EventID = b.EventID
ORDER BY UserID, ContactID, SMSID, EventID, CreatedDate DESC

但是,我不确定如何在识别出这些重复项后删除它们。

这是一些示例数据:

【问题讨论】:

  • 当您说"according to the most recent row" 时,您的意思是在重复的情况下,您想保留最近的记录吗?您能给我们展示一些示例数据吗?
  • 是的,没错。我只想保留最近的副本。所以我对最近的 CreatedDate 很感兴趣。我在原始帖子中添加了一些示例数据的屏幕截图。再次感谢。

标签: mysql


【解决方案1】:

这是一个使用 DELETE FROM JOIN 的解决方案,带有完整的数据演示。

SQL:

-- Data preparation
create table WhenToText(UserID int, ContactID int, SMSID int, EventID int, CreatedDate datetime);
insert into WhenToText values
    (4,   25,  7934, 7407, '2016-02-10 00:00:11'),
    (4,   25,  7934, 7407, '2016-02-09 00:00:12'),
    (4,   29,  5132, 7407, '2016-02-10 00:00:11'),
    (4,   29,  5132, 7407, '2016-02-09 00:00:12'),
    (4,   31, 12944, 7405, '2016-02-10 07:03:02'),
    (4,   31, 12944, 7405, '2016-02-10 05:03:02'),
    (4,  146, 12908, 7405, '2016-02-10 06:52:02'),
    (4,  146, 12908, 7405, '2016-02-10 04:52:02'),
    (15,  63, 12964, 7401, '2016-02-10 03:42:04'),
    (15,  63, 12964, 7401, '2016-02-10 03:41:04'),
    (15,  64, 12326, 7401, '2016-02-07 03:01:03'),
    (15,  64, 12326, 7401, '2016-02-07 03:00:03');
SELECT * FROM WhenToText;

-- SQL needed
DELETE a FROM 
    WhenToText a INNER JOIN
    (
     SELECT UserID, ContactID, SMSID, EventID, MAX(CreatedDate) CreatedDate
     FROM WhenToText
     GROUP BY UserID, ContactID, SMSID, EventID
     ) b
    USING(UserID, ContactID, SMSID, EventID)
WHERE 
    a.CreatedDate != b.CreatedDate;

SELECT * FROM WhenToText;

输出:

mysql> SELECT * FROM WhenToText;
+--------+-----------+-------+---------+---------------------+
| UserID | ContactID | SMSID | EventID | CreatedDate         |
+--------+-----------+-------+---------+---------------------+
|      4 |        25 |  7934 |    7407 | 2016-02-10 00:00:11 |
|      4 |        25 |  7934 |    7407 | 2016-02-09 00:00:12 |
|      4 |        29 |  5132 |    7407 | 2016-02-10 00:00:11 |
|      4 |        29 |  5132 |    7407 | 2016-02-09 00:00:12 |
|      4 |        31 | 12944 |    7405 | 2016-02-10 07:03:02 |
|      4 |        31 | 12944 |    7405 | 2016-02-10 05:03:02 |
|      4 |       146 | 12908 |    7405 | 2016-02-10 06:52:02 |
|      4 |       146 | 12908 |    7405 | 2016-02-10 04:52:02 |
|     15 |        63 | 12964 |    7401 | 2016-02-10 03:42:04 |
|     15 |        63 | 12964 |    7401 | 2016-02-10 03:41:04 |
|     15 |        64 | 12326 |    7401 | 2016-02-07 03:01:03 |
|     15 |        64 | 12326 |    7401 | 2016-02-07 03:00:03 |
+--------+-----------+-------+---------+---------------------+
12 rows in set (0.00 sec)

mysql>
mysql> -- SQL needed
mysql> DELETE a FROM
    ->     WhenToText a INNER JOIN
    ->     (
    ->      SELECT UserID, ContactID, SMSID, EventID, MAX(CreatedDate) CreatedDate
    ->      FROM WhenToText
    ->      GROUP BY UserID, ContactID, SMSID, EventID
    ->      ) b
    ->     USING(UserID, ContactID, SMSID, EventID)
    -> WHERE
    ->     a.CreatedDate != b.CreatedDate;

SELECT * FQuery OK, 6 rows affected (0.00 sec)

mysql>
mysql> SELECT * FROM WhenToText;
+--------+-----------+-------+---------+---------------------+
| UserID | ContactID | SMSID | EventID | CreatedDate         |
+--------+-----------+-------+---------+---------------------+
|      4 |        25 |  7934 |    7407 | 2016-02-10 00:00:11 |
|      4 |        29 |  5132 |    7407 | 2016-02-10 00:00:11 |
|      4 |        31 | 12944 |    7405 | 2016-02-10 07:03:02 |
|      4 |       146 | 12908 |    7405 | 2016-02-10 06:52:02 |
|     15 |        63 | 12964 |    7401 | 2016-02-10 03:42:04 |
|     15 |        64 | 12326 |    7401 | 2016-02-07 03:01:03 |
+--------+-----------+-------+---------+---------------------+
6 rows in set (0.00 sec)

【讨论】:

  • 这似乎是一个不错的方法。有没有在执行之前测试它的好方法?我尝试将其作为 SELECT * FROM 运行,以尝试返回所有将被删除但无法正常工作的行。任何想法?再次感谢!
  • @David 根据您的新数据更新了帖子。请再试一次。
  • 太棒了,这行得通!感谢您在这里的帮助,非常感谢。只是好奇——有没有一种方法可以自动输入 CREATE TABLE 的表,还是必须手动完成?理想情况下,我希望能够一步直接查询,而不必手动输入。
  • 我没听懂。输出只是一个演示。你只需要在你的桌子上使用 DELETE。
【解决方案2】:

这应该提供您正在寻找的解决方案,因为 CreatedDate 是一个日期数据类型。这也是假设最近的行在技术上是最近的 CreatedDate。

SELECT UserID, ContactID, SMSID, EventID, MAX(CreatedDate) AS CreatedDate
FROM WhenToText 
GROUP BY 1, 2, 3, 4;

使用这些值,您可以覆盖 WhenToText 表...看起来像这样...

CREATE TABLE tmp_table LIKE WhenToText;

INSERT INTO tmp_table (SELECT UserID, ContactID, SMSID, EventID, MAX(CreatedDate) AS CreatedDate
                          FROM WhenToText 
                          GROUP BY 1, 2, 3, 4);

TRUNCATE WhenToText;

INSERT INTO WhenToText (SELECT * FROM tmp_table);

DROP TABLE tmp_table;

【讨论】:

  • 我刚刚尝试使用它,它一直说我不能“在 CreatedDate 上分组。”
  • 另外,我尝试进行一些调整,例如用 ORDER BY 替换 GROUP BY,查询只返回 1 行(即 MAX(CreatedDate)。
  • 第一个问题:@David 不确定您是如何得到 GROUP BY 错误的,因为它没有明确地对该项目进行分组。如果它们是 select 语句中的前 4 个项目,则 1、2、3、4 仅指项目(UserID、ContactID、SMSID、EventID)。第二个问题:您需要 GROUP BY 语句才能正确运行聚合 MAX 函数...抛出 ORDER BY 子句而不是 GROUP BY 会混淆聚合,并且只会返回一行。
【解决方案3】:

这是一种方法:

DELETE FROM WhenToText w1
INNER JOIN
(
    SELECT UserID, ContactID, SMSID, EventID, MAX(CreatedDate) AS MaxDate
    FROM WhenToText
    GROUP BY UserID, ContactID, SMSID, EventID
) w2
    ON w1.UserID = w2.UserID AND w1.ContactID = w2.ContactID AND w1.SMSID = w2.SMSID
        AND w1.EventID = w2.EventID
        AND w1.CreatedDate != w2.MaxDate

这将删除给定(UserID, ContactID, SMSID, EventID) 组的所有记录,其CreatedDate 不是最新的。请记住,如果共享最新的CreatedDate,这可能会为每个组留下多个记录。

如果您想先测试哪个查询以查看哪些记录将被删除,您可以将DELETE FROM WhenToText w1 替换为SELECT w1.* FROM WhenToText w1

这是一个 SQL Fiddle 的链接,它演示了查询如何识别要删除的记录:

SQLFiddle

【讨论】:

  • 非常感谢。这正是我想要的。
猜你喜欢
  • 2021-01-31
  • 2021-09-11
  • 1970-01-01
  • 1970-01-01
  • 2011-11-26
  • 1970-01-01
  • 2021-09-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多