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