首页 > 解决方案 > 删除行,同时使用 SQL (MySQL) 保留具有最旧日期条目的行

问题描述

我在 MySQL InnoDB 数据库中有几百万个数据库行需要清理。看看这个例子。

SELECT archiveid, clearingid, pickdate 
  FROM tblclearingarchive 
  WHERE clearingid = 30978729 
  ORDER BY pickdate;


+-----------+------------+---------------------+
| archiveid | clearingid | pickdate            |
+-----------+------------+---------------------+
|  34328367 |   30978729 | NULL                | *
|  34333844 |   30978729 | 2015-10-27 15:55:30 | <- keep only this row with oldest date
|  34438038 |   30978729 | 2016-03-01 10:34:25 | *
|  34481472 |   30978729 | 2016-04-20 13:44:19 | *
+-----------+------------+---------------------+
4 rows in set (0.01 sec)

所以我知道受影响字段的clearingid值,并希望删除没有pickdate(null)的字段和多余的两行(稍后,在第一次选择之后)。在上面的示例中,标有 * 的应该被删除。

有关此类 SQL 更新/删除可能是什么样子的任何提示?

大约有 30M 行和大约 250K 行(已知的 clearingid)需要清理。

谢谢!!!

更新:

有了 Matias Barrios 的最初想法,我找到了这个解决方案来验证。它完美地列出了我要删除的行:

SELECT archiveid, clearingid, pickdate 
  FROM tblclearingarchive 
  WHERE clearingid = 30978729 
  AND (pickdate NOT IN (SELECT MIN(pickdate)
                        FROM tblclearingarchive 
                        WHERE clearingid = 30978729 ) 
       OR pickdate is NULL)
  ORDER BY pickdate;

+-----------+------------+---------------------+
| archiveid | clearingid | pickdate            |
+-----------+------------+---------------------+
|  34328367 |   30978729 | NULL                |
|  34438038 |   30978729 | 2016-03-01 10:34:25 |
|  34481472 |   30978729 | 2016-04-20 13:44:19 |
+-----------+------------+---------------------+
3 rows in set (0.20 sec)

但我无法使用这种查询删除:

DELETE FROM tblclearingarchive 
  WHERE clearingid = 30978729 
  AND (pickdate NOT IN (SELECT MIN(pickdate)
                        FROM tblclearingarchive 
                        WHERE clearingid = 30978729 ) 
      OR pickdate is NULL);

ERROR 1093 (HY000): 您不能在 FROM 子句中指定目标表 'tblclearingarchive' 进行更新

标签: mysqlsqlselect

解决方案


您将需要这样做:

创建“协助表”,以便您可以进行删除

create table test as 
select * from tblclearingarchive

然后进行删除:

delete from tblclearingarchive t1
where t1.pickdate <> (select min(t.pickdate) 
                     from test t
                     group by clearingid)
or t1.pickdate is null;

这是一个小演示


推荐阅读