Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >MySQL 如何查找删除重复行?

MySQL 如何查找删除重复行?

作者头像
芋道源码
发布于 2019-10-22 15:25:21
发布于 2019-10-22 15:25:21
5.9K00
代码可运行
举报
文章被收录于专栏:芋道源码1024芋道源码1024
运行总次数:0
代码可运行

如何查找重复行

第一步是定义什么样的行才是重复行。多数情况下很简单:它们某一列具有相同的值。本文采用这一定义,或许你对“重复”的定义比这复杂,你需要对sql做些修改。本文要用到的数据样本:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
create table test(id int not null primary key, day date not null);

insert into test(id, day) values(1, '2006-10-08');
insert into test(id, day) values(2, '2006-10-08');
insert into test(id, day) values(3, '2006-10-09');

select * from test;
+----+------------+
| id | day        |
+----+------------+
|  1 | 2006-10-08 |
|  2 | 2006-10-08 |
|  3 | 2006-10-09 |
+----+------------+

前面两行在day字段具有相同的值,因此如何我将他们当做重复行,这里有一查询语句可以查找。查询语句使用GROUP BY子句把具有相同字段值的行归为一组,然后计算组的大小。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select day, count(*) from test GROUP BY day;
+------------+----------+
| day        | count(*) |
+------------+----------+
| 2006-10-08 |        2 |
| 2006-10-09 |        1 |
+------------+----------+

重复行的组大小大于1。如何希望只显示重复行,必须使用HAVING子句,比如

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select day, count(*) from test group by day HAVING count(*) > 1;
+------------+----------+
| day        | count(*) |
+------------+----------+
| 2006-10-08 |        2 |
+------------+----------+

这是基本的技巧:根据具有相同值的字段分组,然后知显示大小大于1的组。

为什么不能使用WHERE子句?因为WHERE子句过滤的是分组之前的行,HAVING子句过滤的是分组之后的行。

如何删除重复行

一个相关的问题是如何删除重复行。一个常见的任务是,重复行只保留一行,其他删除,然后你可以创建适当的索引,防止以后再有重复的行写入数据库

同样,首先是弄清楚重复行的定义。你要保留的是哪一行呢?第一行,或者某个字段具有最大值的行?本文中,假设要保留的是第一行——id字段具有最小值的行,意味着你要删除其他的行。

也许最简单的方法是通过临时表。尤其对于MYSQL,有些限制是不能在一个查询语句中select的同时update一个表。简单起见,这里只用到了临时表的方法。

我们的任务是:删除所有重复行,除了分组中id字段具有最小值的行。因此,需要找出大小大于1的分组,以及希望保留的行。你可以使用MIN()函数。这里的语句是创建临时表,以及查找需要用DELETE删除的行。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
create temporary table to_delete (day date not null, min_id int not null);

insert into to_delete(day, min_id)
  select day, MIN(id) from test group by day having count(*) > 1;

select * from to_delete;
+------------+--------+
| day        | min_id |
+------------+--------+
| 2006-10-08 |      1 |
+------------+--------+

有了这些数据,你可以开始删除“脏数据”行了。可以有几种方法,各有优劣(详见我的文章many-to-one problems in SQL),但这里不做详细比较,只是说明在支持查询子句的关系数据库中,使用的标准方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
delete from test
  where exists(
     select * from to_delete
     where to_delete.day = test.day and to_delete.min_id <> test.id
  )

如何查找多列上的重复行

有人最近问到这样的问题:我的一个表上有两个字段b和c,分别关联到其他两个表的b和c字段。我想要找出在b字段或者c字段上具有重复值的行。

乍看很难明白,通过对话后我理解了:他想要对b和c分别创建unique索引。如上所述,查找在某一字段上具有重复值的行很简单,只要用group分组,然后计算组的大小。并且查找全部字段重复的行也很简单,只要把所有字段放到group子句。但如果是判断b字段重复或者c字段重复,问题困难得多。这里提问者用到的样本数据

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
create table a_b_c(
  a int not null primary key auto_increment,
  b int,
  c int
);

insert into a_b_c(b,c) values (1, 1);
insert into a_b_c(b,c) values (1, 2);
insert into a_b_c(b,c) values (1, 3);
insert into a_b_c(b,c) values (2, 1);
insert into a_b_c(b,c) values (2, 2);
insert into a_b_c(b,c) values (2, 3);
insert into a_b_c(b,c) values (3, 1);
insert into a_b_c(b,c) values (3, 2);
insert into a_b_c(b,c) values (3, 3);

现在,你可以轻易看到表里面有一些重复的行,但找不到两行具有相同的二元组{b, c}。这就是为什么问题会变得困难了。

错误的查询语句

如果把两列放在一起分组,你会得到不同的结果,具体看如何分组和计算大小。提问者恰恰是困在了这里。有时候查询语句找到一些重复行却漏了其他的。这是他用到了查询

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select b, c, count(*) from a_b_c
group by b, c
having count(distinct b > 1)
  or count(distinct c > 1);

结果返回所有的行,因为CONT(*)总是1.为什么?因为 >1 写在COUNT()里面。这个错误很容易被忽略,事实上等效于

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select b, c, count(*) from a_b_c
group by b, c
having count(1)
  or count(1);

为什么?因为(b > 1)是一个布尔值,根本不是你想要的结果。你要的是

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select b, c, count(*) from a_b_c
group by b, c
having count(distinct b) > 1
  or count(distinct c) > 1;

返回空结果。很显然,因为没有重复的{b,c}。这人试了很多其他的OR和AND的组合,用来分组的是一个字段,计算大小的是另一个字段,像这样

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select b, count(*) from a_b_c group by b having count(distinct c) > 1;
+------+----------+
| b    | count(*) |
+------+----------+
|    1 |        3 |
|    2 |        3 |
|    3 |        3 |
+------+----------+

没有一个能够找出全部的重复行。而且最令人沮丧的是,对于某些情况,这种语句是有效的,如果错误地以为就是这么写法,然而对于另外的情况,很可能得到错误结果。

事实上,单纯用GROUP BY 是不可行的。为什么?因为当你对某一字段使用group by时,就会把另一字段的值分散到不同的分组里。对这些字段排序可以看到这些效果,正如分组做的那样。首先,对b字段排序,看看它是如何分组的

当你对b字段排序(分组),相同值的c被分到不同的组,因此不能用COUNT(DISTINCT c)来计算大小。COUNT()之类的内部函数只作用于同一个分组,对于不同分组的行就无能为力了。类似,如果排序的是c字段,相同值的b也会分到不同的组,无论如何是不能达到我们的目的的。

几种正确的方法

也许最简单的方法是分别对某个字段查找重复行,然后用UNION拼在一起,像这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select b as value, count(*) as cnt, 'b' as what_col
from a_b_c group by b having count(*) > 1
union
select c as value, count(*) as cnt, 'c' as what_col
from a_b_c group by c having count(*) > 1;
+-------+-----+----------+
| value | cnt | what_col |
+-------+-----+----------+
|     1 |   3 | b        |
|     2 |   3 | b        |
|     3 |   3 | b        |
|     1 |   3 | c        |
|     2 |   3 | c        |
|     3 |   3 | c        |
+-------+-----+----------+

输出what_col字段为了提示重复的是哪个字段。另一个办法是使用嵌套查询:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select a, b, c from a_b_c
where b in (select b from a_b_c group by b having count(*) > 1)
   or c in (select c from a_b_c group by c having count(*) > 1);
+----+------+------+
| a  | b    | c    |
+----+------+------+
|  7 |    1 |    1 |
|  8 |    1 |    2 |
|  9 |    1 |    3 |
| 10 |    2 |    1 |
| 11 |    2 |    2 |
| 12 |    2 |    3 |
| 13 |    3 |    1 |
| 14 |    3 |    2 |
| 15 |    3 |    3 |
+----+------+------+

这种方法的效率要比使用UNION低许多,并且显示每一重复的行,而不是重复的字段值。还有一种方法,将自己跟group的嵌套查询结果联表查询。写法比较复杂,但对于复杂的数据或者对效率有较高要求的情况,是很有必要的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select a, a_b_c.b, a_b_c.c
from a_b_c
  left outer join (
     select b from a_b_c group by b having count(*) > 1
  ) as b on a_b_c.b = b.b
  left outer join (
     select c from a_b_c group by c having count(*) > 1
  ) as c on a_b_c.c = c.c
where b.b is not null or c.c is not null

以上方法可行,我敢肯定还有其他的方法。如果UNION能用,我想会是最简单不过的了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 芋道源码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Mysql数据库总结
– 1.创建数据库 CREATE DATABASE mybase; – 2.创建数据库并指定字符集 CREATE DATABASE mybase1 CHARACTER SET UTF8; – 3.查看所有数据库 SHOW DATABASES; – 4.查看当前使用的数据库 SELECT DATABASE(); – 5.修改数据库 ALTER DATABASE mybase CHARACTER SET UTF8; – 6.删除数据库 DROP DATABASE mybase1; – 切换数据库 USE mybase;
Twcat_tree
2022/11/30
3740
Mysql数据库总结
MySQL表的增删查改
values左侧为表中属性,右侧为自定义插入的内容,左右两侧安装顺序是一一对应的,如果顺序不同就会导致类型不同而出错。
每天都要进步呀
2023/10/16
4420
MySQL表的增删查改
学会Mysql第二天
完整的SQL查询指令: select select选项 字段列表 from 数据源 where条件 group by 分组 having 条件 order by 排序 limit 限制
白胡杨同学
2020/04/11
8310
简单的增 删 改 查
一:insert语句 into 关键字是可选的 values关键字前面的()是可选的,这里是要接收数据的列 values后面,有两种方式提供值 1:显式的给出值  2:从select语句中导出值
liulun
2022/05/08
5290
MySQL基础 — 常用命令
使用select对列进行查询时,不仅可以直接以列的原始值作为结果,而且还可以将列值进行计算后所得值作为查询结果,即select子句可以查询表达式的值,表达式可由列名、常量及算术运算符组成。 查询结果计算列显示“无列名”,一般要给计算列加列标题。 其中:表达式中可以使用的运算符有:加+、减-、乘*、除/、取余%
全栈程序员站长
2022/07/02
2.1K0
MySQL基础 — 常用命令
【MySql】聚合函数&&group by&&OJ题目
MySQL中的聚合函数用于对数据进行计算和统计,常见的聚合函数包括下面列举出来的聚合函数:
平凡的人1
2023/10/15
2510
【MySql】聚合函数&&group by&&OJ题目
《数据库查询:解锁数据宝藏的魔法之钥》
MySQL查询是一种用于检索、筛选和分析数据的数据库操作技术。作为一个强大的关系型数据库管理系统(RDBMS),MySQL支持多种查询方法,包括使用SQL(Structured Query Language)编写的查询语句。
杨不易呀
2023/09/27
2330
《数据库查询:解锁数据宝藏的魔法之钥》
2024Mysql And Redis基础与进阶操作系列(5)作者——LJS[含MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页等详解步骤及常见报错问题所对应的解决方法]
学生表中存在一个birth字段,这个字段表示学生的出生年份。而运用MySQL的算术运算符用当前的年份减学生出生的年份,那么得到的就是这个学生的实际年龄数据。
盛透侧视攻城狮
2024/10/22
3050
2024Mysql And Redis基础与进阶操作系列(5)作者——LJS[含MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页等详解步骤及常见报错问题所对应的解决方法]
数据仓库开发 SQL 使用技巧总结
作者:dcguo 使用 sql 做数仓开发有一段时间了,现做一下梳理复盘,主要内容包括 sql 语法、特性、函数、优化、特殊业务表实现等。 mysql 数据结构 常用 innodb 存储为 B+ 树 特点 多路平衡树,m 个子树中间节点就包含 m 个元素,一个中间节点是一个 page(磁盘页) 默认 16 kb; 子节点保存了全部得元素,父节点得元素是子节点的最大或者最小元素,而且依然是有序得; 节点元素有序,叶子节点双向有序,便于排序和范围查询。 优势 平衡查找树,logn 级别 crud; 单一节点比二
腾讯技术工程官方号
2022/07/19
3.3K0
数据仓库开发 SQL 使用技巧总结
阶段02JavaWeb基础day04mysql
数据仓库.就与我们之前学过的纯文本,properties这些技术一样.用来保存数据.并提供对数据进行增删改查的操作.我们以后做项目时, 项目中的数据都是保存在数据库中的. //-------------------------------------------------------------------- 为什么要用数据库,数据库的特点 1>实现数据共享
对弈
2019/09/04
5610
MySQL秘籍之索引与查询优化实战指南
最左前缀原则。不冗余原则。最大选择性原则。所谓前缀索引,说白了就是对文本的前几个字符建立索引(具体是几个字符在建立索引时去指定),比如以产品名称的前 10 位来建索引,这样建立起来的索引更小,查询效率更快!
千寻简
2025/01/03
2510
MySQL秘籍之索引与查询优化实战指南
Mysql入门
主流数据库包括:MS SQL Server, Oracle,DB2,Informix, Sybase 等。
jinghong
2020/05/12
1.3K0
Mysql入门
sql server之数据库语句优化
一切都是为了性能,一切都是为了业务 一、查询的逻辑执行顺序 (1) FROM left_table (3) join_type JOIN right_table (2) ON join_condition (4) WHERE where_condition (5) GROUP BY group_by_list (6) WITH {cube | rollup} (7) HAVING having_condition (8) SELECT (9) DISTINCT (11) top_specification
逸鹏
2018/04/09
1.6K0
MySQL 从入门到实践,万字详解!
数据库是往全栈发展不得不跨过的一道坎,大家不可避免会学到用到相关知识,最近查资料的时候发现网上很多内容要么就特别深,要么不成体系,对一些希望浅尝辄止仅仅是使用一下的人不太友好。最近刚好有机会学到 MySQL,集中一些时间学习了一下 MySQL 同时做了一些笔记,每个概念基本都有代码示例,每一行都是在下手打,读者可以直接复制了代码到命令行中运行,希望对大家有所帮助~ 😜 本文介绍的知识都不是特别深,目标用户是对 MySQL 零基础或弱基础的小伙伴们,可以帮助对 MySQL 建立一些概念,至少碰到相关问题知道
前端下午茶
2022/03/22
2.1K0
MySQL 从入门到实践,万字详解!
MySQL(四)
基本语法: insert into {表名}({字段列表}) values({值列表1}), ({值列表2}), …
1ess
2021/11/01
9940
【云原生进阶之数据库技术】第一章MySQL-2.3-数据基本操作
2、语法:select distinct from 表名; 去掉重复项,对应的字段前加符号表达:
江中散人_Jun
2024/02/24
2110
【云原生进阶之数据库技术】第一章MySQL-2.3-数据基本操作
Vc数据库编程基础MySql数据库的表查询功能
  不管是任何数据库.都会有查询功能.而且是很重要的功能.上一讲知识简单的讲解了表的查询所有.
IBinary
2019/05/25
9.8K0
理解SQL原理SQL调优你必须知道的10条铁律
原文地址: http://www.nowamagic.net/librarys/veda/detail/1502 我们做软件开发的,大部分人都离不开跟数据库打交道,特别是erp开发的,跟数据库打交道更是频繁,存储过程动不动就是上千行,如果数据量大,人员流动大,那么我们还能保证下一段时间系统还能流畅的运行吗?我们还能保证下一个人能看懂我们的存储过程吗? 要知道sql语句,我想我们有必要知道sqlserver查询分析器怎么执行我么sql语句的,我么很多人会看执行计划,或者用profile来监视和调优查询语句或
Albert陈凯
2018/04/04
1.3K0
MySQL基础学习笔记
1.基础概念 1.1 相关概念与常用命令 数据库的好处 1.持久化数据到本地 2.可以实现结构化查询,方便管理 常见概念 1、DB:数据库,保存一组有组织的数据的容器 2、DBMS:数据库管理系统,又称为数据库软件(产品),用于管理DB中的数据 3、SQL: 结构化查询语言,用于和DBMS通信的语言 数据库存储数据的特点 1、将数据放到表中,表再放到库中 2、一个数据库中可以有多个表,每个表都有一个的名字,用来标识自己。表名具有唯一性。 3、表具有一些特性,这些特性定义了数据在表中如何存储,类似java中“
素履coder
2022/02/17
1.1K0
MySQL数据库完整知识点梳理----保姆级教程!!!
在字段名前面加上DISTINCT ,这里对于重复的字段,就只会显示最先出现的那个,后面重复的不会显示
大忽悠爱学习
2021/11/15
6K0
相关推荐
Mysql数据库总结
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验