PHP笔记网

革命尚未成功,同志仍须努力下载JDK17

作者:Albert.Wen  添加时间:2020-03-21 11:52:46  修改时间:2024-11-20 10:34:25  分类:MySQL/Redis  编辑

推荐先去搞懂:MySQL where 和 having 的区别


MySQL中常用去重复数据的方法是使用 distinct  或者 group by ,以上2种均能实现,但2者也有不同的地方。

distinct 特点:

如:select distinct name, sex from tb_students  这个sql的语法中,查询 tb_students  表中 name, sex 并去除名字和性别都重复的学生:

1、distinct 只能放在查询字段的最前面,不能放在查询字段的中间或者后面。

备注:select sex, distinct name from tb_students  这种写法是错误的,distinct 只能写在所有查询字段的前面

2、distinct 对后面所有的字段均起作用,即 去重是查询的所有字段完全重复的数据,而不是只对 distinct 后面连接的单个字段重复的数据。

备注:也就是 distinct 关键字对 name, sex 都起作用,去重姓名、性别完全一样的学生,如果姓名相同、性别不同是不会去重的。

3、要查询多个字段,但只针对一个字段去重,使用 distinct 去重的话是无法实现的。

group by 特点:

1、一般与聚类函数使用(如count()/sum()等),也可单独使用。

2、group by 也对后面所有的字段均起作用,即 去重是查询的所有字段完全重复的数据,而不是只对 group by 后面连接的单个字段重复的数据。

3、查询的字段与 group by 后面分组的字段没有限制。

特别说明:在 Oracle 中使用 group by 时,查询的字段必须是 group by 分组的字段和聚类函数。如 select name, sex from tb_students group by name 这个 sql 语法在 Oracle 中是错误的,因为 sex 不在 group by 分组后面,但在 MySQL 中是支持的。

 


distinct 与 group by 的一些示例

在数据表中记录了用户验证时使用的书目,现在想取出所有书目,用 distinct 和 group by 都取到了我想要的结果,但返回结果排列不同,distinct 会按数据存放顺序一条条显示,而 group by 会做个排序(一般是asc)。

distinct 实际上和 group by 操作的实现非常相似,只不过是在 group by 之后的每组中只取出一条记录而已。所以,distinct 的实现和 group by 的实现也基本差不多,没有太大的区别,同样可以通过松散索引扫描或者是紧凑索引扫描来实现。 

那 distinct 和 group by 哪个效率更高?

distinct 操作只需要找出所有不同的值就可以了。而 group by 操作还要为其他聚集函数进行准备工作。从这一点上将,group by 操作做的工作应该比 distinct 所做的工作要多一些。  

但实际上,group by 效率会更高点,为什么呢?对于distinct操作,它会读取了所有记录,而 group by 需要读取的记录数量与分组的组数量一样多,也就是说比实际存在的记录数目要少很多。

下面来看 MySQL 中 distinct 及 group by 的一些用法分享。

CREATE TABLE `student` (          
      `name` varchar(20) NOT NULL DEFAULT '', 
      `age` int(10) DEFAULT '0'        
) ENGINE=InnoDB DEFAULT CHARSET=latin1

1. 测试一

select * from student; 

返回

a  5
a  5
c  0

用 distinct 过滤掉两列都相同的记录

select distinct name,age from student;

返回

a  5
c  0

2. 测试二

将表 student 的数据改为如下:

select * from student;
c  2
c  5
select distinct name,age from student;

返回如下,说明 distinct 后面有多于一列的字段时,只有所有查询列的值完全相同才过滤

c  2
c  5

3. 测试三

select * from student;

返回

name age height
c  2  123
c  2  456
b  20  222

group by 按两列同时分组

select name,age,sum(height) from student group by name,age;

返回

b  20  222
c  2  579

group by 按两列同时分组,同时在后面加上 having 的条件

select name,age,sum(height) as n from student group by name,age having n > 500;

返回

c    2    579

4. 测试四

关于 group by 后面 limit 的测试

select songname,sengerid,count(sengerid) as n from t_song group by songname,sengerid having n > 1 ORDER BY n DESC,songid ASC limit 10;

返回

未知  8738  40
共同渡过  1432  24
风继续吹  1432  23
倩女幽魂  1432  23
无心睡眠  1432  23
罗百吉超嗨派对连续组曲  780  19
拒绝再玩  1432  19
风再起时  1432  18
每天爱你多一些  1480  18
千言万语  1794  18

 

select songname,sengerid,count(sengerid) as n from t_song group by songname,sengerid having n > 1 ORDER BY n DESC,songid ASC limit 5;

返回

未知  8738  40
共同渡过  1432  24
风继续吹  1432  23
倩女幽魂  1432  23
无心睡眠  1432  23

经过以上两个测试可以看出,如果 sql 语句中含有 limit,limit 是对用 group by 进行分组,并进行相关计算以后的 limit 操作,而不是对 limit 后面的指定记录数进行分组,从 n 那一列的数据每一行的值都大于 10就可以看出来。

5. 测试五

用以下的两种形式的 distinct 均可以得到相同的记录数,写法不一样,结果是一样的。

select count(distinct(songid)) from feedback;
select count(distinct songid) from feedback;

6. 测试六

field singername is string, max(singername),如果 singername 有些列为空,有些列不为空,则 max(singername) 取非空的值,如果一列值为'zxx', 一列值为'lady',则取'zxx',按字母顺利取的。

select feedback_id,songid,songname,max(singername),max(time) as new_time from feedback group by songid order by new_time desc;

7. Sql 语句中 where, group by, order by 及 limit 的顺序

where xxx,group by xxx,order by xxx,limit xxx

8. 关于 group by 与 count 的问题

如果 sql 语句中含有 group by,则最好不要将 count sql 转换为 select count(*) from xxx,否则 select 与 from 之间的字段很有可能是后面要使用的,例如:

select feedback_id,songid,songname,max(singername),max(time) as new_time from feedback group by songid order by new_time desc;

返回

MySQL Query Error: SELECT COUNT(*) FROM feedback group by songid ORDER BY new_time DESC Error Info:Unknown column 'new_time' in 'order clause'

 

 

参考:

  1. https://www.cnblogs.com/whitemouseV2-0/p/11226444.html
  2. https://www.jb51.net/article/78000.htm