Mysql篇:MySQL distinct 与 group by 去重(where/having)

本文详细比较了MySQL中distinct和groupby去重的区别,包括distinct的使用限制、groupby的灵活性以及效率分析。作者通过示例展示了distinct和groupby在实际场景中的应用,指出groupby通常效率更高,尤其是在配合limit时。
摘要由CSDN通过智能技术生成

MySQL distinct 与 group by 去重(where/having)

mysql中常用的去重数据的方法是使用distinct 或者 使用 group by 这两种。这两种实现方法也有不同的地方。

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 的一些用法分享。

1

2

3

4

CREATE TABLE `student` (         

      `name` varchar(20) NOT NULL DEFAULT '',

      `age` int(10) DEFAULT '0'       

) ENGINE=InnoDB DEFAULT CHARSET=latin1

1. 测试一

1

select * from student;

返回

1

2

3

a  5

a  5

c  0

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

1

select distinct name,age from student;

返回

1

2

a  5

c  0

2. 测试二

将表 student 的数据改为如下:

1

select * from student;

1

2

c  2

c  5

1

select distinct name,age from student;

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

1

2

c  2

c  5

3. 测试三

1

select * from student;

返回

1

2

3

4

name age height

c  2  123

c  2  456

b  20  222

group by 按两列同时分组

1

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

返回

1

2

b  20  222

c  2  579

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

1

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

返回

1

c    2    579

4. 测试四

关于 group by 后面 limit 的测试

1

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;

返回

1

2

3

4

5

6

7

8

9

10

未知  8738  40

共同渡过  1432  24

风继续吹  1432  23

倩女幽魂  1432  23

无心睡眠  1432  23

罗百吉超嗨派对连续组曲  780  19

拒绝再玩  1432  19

风再起时  1432  18

每天爱你多一些  1480  18

千言万语  1794  18

1

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;

返回

1

2

3

4

5

未知  8738  40

共同渡过  1432  24

风继续吹  1432  23

倩女幽魂  1432  23

无心睡眠  1432  23

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

5. 测试五

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

1

2

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',按字母顺利取的。

1

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 的顺序

1

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 之间的字段很有可能是后面要使用的,例如:

1

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

返回

1

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

  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值