如何用单条SQL语句删除按DateInserted排序后非连续的重复RecordID记录
实现方案
可以通过单条查询语句实现该需求,核心思路是用窗口函数标记连续的RecordID分组,过滤出非首次出现的分组对应的记录删除即可,支持窗口函数的数据库(MySQL 8.0+、PostgreSQL、SQL Server等)均可直接适配,以下是具体实现:
实现逻辑
- 按
DateInserted升序排序后,用LAG()窗口函数获取上一条记录的RecordID,标记当前记录是否为新连续分组的边界 - 对边界标记做累加求和,给每个连续的相同
RecordID分组分配唯一的组号 - 匹配每个
RecordID首次出现的最小组号,所有组号大于最小组号的同RecordID记录即为需要删除的非连续重复记录
示例代码(MySQL语法)
DELETE t FROM 你的表名 t JOIN ( WITH grouped_data AS ( SELECT ID, RecordID, SUM(CASE WHEN pre_record_id != RecordID THEN 1 ELSE 0 END) OVER(ORDER BY DateInserted) AS group_id FROM ( SELECT ID, RecordID, LAG(RecordID) OVER(ORDER BY DateInserted) AS pre_record_id FROM 你的表名 ) AS t1 ), first_group AS ( SELECT RecordID, MIN(group_id) AS first_group_id FROM grouped_data GROUP BY RecordID ) SELECT grouped_data.ID FROM grouped_data JOIN first_group ON grouped_data.RecordID = first_group.RecordID WHERE grouped_data.group_id > first_group.first_group_id ) AS to_delete ON t.ID = to_delete.ID
效果验证
你提供的示例数据中,按逻辑计算出的分组结果如下:
| ID | RecordID | group_id | 所属RecordID的首次组号 | 是否删除 |
|---|---|---|---|---|
| 1 | 10 | 1 | 1 | 否 |
| 2 | 10 | 1 | 1 | 否 |
| 3 | 4 | 2 | 2 | 否 |
| 4 | 10 | 3 | 1 | 是 |
| 5 | 10 | 3 | 1 | 是 |
完全匹配你需要删除ID为4、5的记录的需求。如果使用不支持CTE的低版本数据库,把CTE替换为嵌套子查询即可,依然可以写成单条语句。
内容的提问来源于stack exchange,提问作者Claudio Ferraro
相关产品推荐
相关产品推荐

