前言
今天需要删除数据库中某个字段(source_id)的重复数据,但是又要保留其中最新的一条,思路是:
根据该字段分组,获取分组中最大的那一条,用not in 包裹,然后执行delete语句。中间遇到了两个问题,第一个就是报错MySql]You can't specify target table for update in FROM clause
,参考博客:https://blog.youkuaiyun.com/jsloveyou/article/details/79024600 解决了,第二个问题是:我写的sql比较复杂,经大佬指点后最终实现如下。
最终实现的sql
DELETE
FROM
draft_video
WHERE
draft_video.id NOT IN (
SELECT
result.id
FROM
(
SELECT
max(d.id) AS id
FROM
draft_video d
GROUP BY
source_id
) AS result
)
中间遇到的问题
问题1:报错:MySql]You can’t specify target table for update in FROM clause
原因:MySQL 修改或者删除数据时候不能以当前表作为 from 条件。
解决方案参考: https://blog.youkuaiyun.com/jsloveyou/article/details/79024600
问题2: 复杂的sql实现
实现思想:
- 根据source_id 分组,having count(source_id)>1的数据,即为数据库中的重复数据
- 根据查询出source_id中重复的sourceId中id最大的数据取出
- 将1,2中的数据进行and连接查询,最终获取结果
DELETE
FROM
draft_video
WHERE
draft_video.source_id IN (
SELECT
r1.source_id
FROM
(
SELECT
source_id
FROM
draft_video
GROUP BY
source_id
HAVING
COUNT(source_id) > 1
) AS r1
)
AND draft_video.id NOT IN (
SELECT
r2.id
FROM
(
SELECT
MAX(draft_video.id) as id
FROM
draft_video
GROUP BY
draft_video.source_id
HAVING
COUNT(draft_video.source_id) > 1
) AS r2
);
可以看到这种实现方式比较臃肿而且性能不好。
大佬的点播
我在高级java技术分享群(821605718,我是群主)分享了这个sql后,有位大佬,给出了最终得sql,并指导我用逆向思维来处理这个问题。大佬原话如下:
没有重复的话那么group by之后 再拿最大的ID是不是就是本身那一条,那有重复的分组之后你拿最大的ID是不是就是你要保留的 。
三人行必有我师焉,欢迎大家愿意学习得朋友一起探讨问题。