【场景题】MySQL删除重复元素

1. 铺垫

在实际生产过程中有很多种原因会导致MySQL中包含着重复的元素,比如下面这三种:

  1. 导数据过程中
  2. openfeign, rabbitMQ的重试机制
  3. 分布式下并发插入的问题

这些重复数据往往id不同其他键值相同或者相近。在这个场景下需要去除重复数据应该怎么做?

2. 使用原生MySQL

对于任意一个数据库,想要删除重复数据,是不是应该先查询出来重复的数据(获取id),然后再根据id来删除重复数据😁
为了模拟场景,给出一个学生表:

CREATE TABLE t_student (
    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
    stu_id INT NOT NULL UNIQUE COMMENT '学生ID,唯一标识',
    name VARCHAR(15) NOT NULL COMMENT '学生姓名',
    age INT COMMENT '学生年龄',
    phone VARCHAR(15) COMMENT '学生电话',
    grade INT COMMENT '学生年级',
    parent_info INT COMMENT '家长信息外键',
    create_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) COMMENT='学生信息表';

#插入数据,重复如下
-- 张三 - 4
-- 李四 - 2
-- 王五 - 2
-- 赵六 - 1
INSERT INTO t_student (stu_id, name, age, phone, grade, parent_info) VALUES
(1001, '张三', 15, '13800138001', 9, 1),
(1002, '李四', 14, '13900139001', 8, 6),
(1003, '张三', 15, '13800138002', 9, 2),
(1004, '张三', 15, '13800138003', 9, 3),
(1005, '王五', 16, '13700137001', 10, 7),
(1006, '赵六', 13, '13600136001', 7, 8),
(1007, '王五', 16, '13400134001', 6, 10);
(1008, '李四', 15, '13800138004', 8, 6),
(1009, '张三', 15, '13800138005', 9, 5);

2.1 根据唯一键值查询重复数据

# 假设name不允许重复,实际生产中替换需求
SELECT `name`, COUNT(name) FROM t_student GROUP BY `name` HAVING COUNT(name) > 1; 

2.2 封装结果获取到完整数据

# 假设name不允许重复,实际生产中替换需求
SELECT * FROM t_student WHERE name IN (
	SELECT `name` FROM t_student GROUP BY `name` HAVING COUNT(name) > 1
);

2.3 重复全删

# 假设name不允许重复,实际生产中替换需求
DELETE FROM t_student WHERE name IN (
	SELECT t.name FROM (
		SELECT `name` FROM t_student GROUP BY `name` HAVING COUNT(name) > 1
    ) t;
);

2.4 根据唯一id删除(保留最早的id)

# 假设name不允许重复,实际生产中替换需求
DELETE FROM t_student WHERE id NOT IN (
	SELECT t.id FROM (
		SELECT MIN(id) AS id FROM t_student GROUP BY `name`
    ) t;
);
### 如何在MySQL删除重复行仅保留一行 为了有效地删除表中的重复记录并只保留单条记录,可以采用多种策略。一种常见且高效的方法是通过创建临时表来保存唯一的数据副本,然后再将其重新导入原表。 #### 方法一:使用临时表法 这种方法涉及三个主要操作: 1. 创建一个新的临时表用于存储不重复的数据; 2. 将原始表中去重后的数据插入新表; 3. 清空旧表并将清理过的数据移回至原来的表结构中; 具体SQL语句如下所示[^1]: ```sql CREATE TABLE temp_table AS SELECT MIN(id) as id, value FROM test_1 GROUP BY value; TRUNCATE TABLE test_1; INSERT INTO test_1 (id, value) SELECT id, value FROM temp_table; DROP TABLE temp_table; ``` 此方法适用于所有列都可能重复的情况,并确保每组相同的`value`只会有一个对应的最小`id`被保留在最终结果里。 #### 方法二:利用子查询与DELETE命令组合 对于只需要基于某些特定字段去除冗余而不影响其他部分的情形,则可以直接运用带有子查询条件的DELETE指令完成目标。例如,在给定的例子中如果希望依据`dname`这一属性过滤掉多余的部门信息,可采取下面的方式[^3]: ```sql DELETE t1 FROM dept t1 LEFT JOIN ( SELECT MIN(id) keep_id, dname FROM dept GROUP BY dname ) t2 ON t1.id = t2.keep_id AND t1.dname=t2.dname WHERE t2.keep_id IS NULL; ``` 上述代码片段实现了对`dept`表内的重复项进行筛选——即针对每一个唯一的`dname`值选取其关联的最低编号(`keep_id`)作为代表元素予以留存,而其余同名却拥有更高ID号者则会被标记为NULL并通过外键约束机制自动清除出去。 这两种方案各有优劣,前者适合于全量更新场景下的彻底清洗工作,后者更侧重局部调整时的应用需求。实际应用过程中可根据具体情况灵活选用最合适的解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值