sql如何先排序再去重

场景

有一张得分表(score),记录了用户每次的得分,同一我的可能有多个得分。sql

id name score
1 tom 45
2 jack 78
3 tom 34
. . .

需求:找出分数最高的前5我的。数据库

SQL1

首先咱们写个最简单的sql:code

select 
    id, name, score
from 
    score
order by 
    score desc
limit 5;

若是sql这样写,结果多是:排序

id name score
2 jack 78
1 tom 45
3 tom 34

排序了,可是没有去重it

SQL2

那么咱们加上去重:table

select 
    distinct name
from 
    score
order by 
    score desc
limit 5;

首先第一点是这个sql未必能执行。在一些数据库版本,这个sql能够被执行,在一些版本则会提示你order by的字段必须在distinct中存在(见SQL3)。class

可是即便能执行,这个sql也得不到预期结果。缘由是distinct优先于order by 被数据库执行。select

在执行distinct name的时候,如上文中的数据。是取id=1的数据,仍是id=3的数据呢?其实这是数据库自行决定的。所以,可能会不正确选择数据。im

好比真的执行这个sql,可能去重的结果是:数据

id name score
2 jack 78
3 tom 34

而后再执行一个order by,就会认为第一名是jack78分,第二名是tom34分。然而其实tom应该是45分,这个45分就在数据库执行distinct的时候被错误的丢弃了,毕竟先执行distinct的时候不知道你到底要哪一个数据。

SQL3

那么咱们把score加入select中呢?

select 
    distinct name, score
from 
    score
order by 
    score desc
limit 5;

很明显,这样写的执行结果和咱们预期不符。由于若是写:distinct name,score其实是对name和score一块儿去重。好比name都是jack,score都是45。那么这行就会被去掉。

可是问题是正由于把score当作去重的条件了。因此对于同名的人,好比都叫tom,会由于其有两个分数,致使不能被去重,从而保留两行记录。结果就是好像没有去重。

SQL4

那我不用distinct,用group by进行去重能够吗?

select 
    name
from 
    score
group by
    name
order by 
    score desc
limit 5;

也不行,由于在group by的时候,数据库仍是不知道对两行name同样的数据,究竟应该留下哪一行。

SQL5

正确的写法:

select 
    name
from 
    score
group by
    name
order by 
    max(score) desc
limit 5;

这样写,在执行group by的时候,数据库就知道要保留score最大的那一行了。

相关文章
相关标签/搜索