MySQL 语句(一) ——去除重复数据,只保留最早一条

前提

假设一种情况,数据库的数据重复了,只想保留最早一条。
比如,书库中《三体》录入了多次,想根据时间戳,只保留第一次入库的记录,也就是张三录入的记录。


在这里插入图片描述

分析

想要删除重复数据,需要找出不合适的数据,根据主键(s_id)删除掉。具体是以下两步:

  1. 找出想保留数据的id
  2. 把其他的数据删除
实现
1、找出想保留数据的id,这一步是最关键的一步

如果数据是自增长的,就比较简单,只需要一句

SELECT min(s_id) id from t_book GROUP BY s_name

到此可以直接看第二步了。
但是如果id是uuid就会变得复杂,需要根据时间排序拿到第一条数据

SELECT min(d_timestamp) time,s_name FROM t_book GROUP BY s_name

这样我们就拿到了同一本书最早的记录,但是缺少id。


在这里插入图片描述

注意:这里不能把 id 直接写在SELECT 中,因为 id 不在GROUP BY后面。如果是 mysql8,强行添加在SELECT 就会报错,需要用 any_value(s_id) 处理,mysql5+ 虽然不会报错,但是和这个方法一样,从字面也能看出来,any_value 就是随便一个值,这样强行放置的结果就是拿到的数据id并不符合 min(d_timestamp) 这个条件。

想要拿到 id,需要再关联原始表。

SELECT t_left.s_name,t_right.s_id,t_right.s_name,t_right.d_timestamp
FROM (SELECT min(d_timestamp) time,s_name FROM t_book GROUP BY s_name) t_left LEFT JOIN t_book t_right  
ON t_left.time=t_right.d_timestamp AND t_left.s_name=t_right.s_name

关联结果:


在这里插入图片描述

这样就拿到了需要保留数据的 id。

2、把其他的数据删除

拿到了需要保留的 id ,就只需要通过 not in 语句删除不在这些 id 里面的数据就行了。一般就会写成如下这种,但是是会报错的

DELETE FROM t_book WHERE s_id not in (
SELECT t_right.s_id
FROM (SELECT min(d_timestamp) time,s_name FROM t_book GROUP BY s_name) t_left LEFT JOIN t_book t_right  
ON t_left.time=t_right.d_timestamp AND t_left.s_name=t_right.s_name
) 

错误信息如下,就是说不能直接操作原表数据

1093 - You can’t specify target table ‘t_book’ for update in FROM clause

解决方法是将当前表重新命名成一个独立的表 t_all,然后从 t_all 里面查询出来 id

SELECT id FROM 
(SELECT t_right.s_id id
FROM (SELECT min(d_timestamp) time,s_name FROM t_book GROUP BY s_name) t_left LEFT JOIN t_book t_right  ON t_left.time=t_right.d_timestamp AND t_left.s_name=t_right.s_name) 
t_all

最终的语句就是

DELETE FROM t_book WHERE s_id not in (
SELECT id FROM 
(SELECT t_right.s_id id
FROM (SELECT min(d_timestamp) time,s_name FROM t_book GROUP BY s_name) t_left LEFT JOIN t_book t_right  ON t_left.time=t_right.d_timestamp AND t_left.s_name=t_right.s_name) 
t_all
)

执行成功


在这里插入图片描述

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值