sql如何先排序再去重
場(chǎng)景
有一張得分表(score),記錄了用戶每次的得分,同一個(gè)人可能有多個(gè)得分。
| 1 | tom | 45 |
| 2 | jack | 78 |
| 3 | tom | 34 |
| . | . | . |
需求:找出分?jǐn)?shù)最高的前5個(gè)人。
SQL1
首先我們寫個(gè)最簡(jiǎn)單的sql:
select id, name, score from score order by score desc limit 5;如果sql這樣寫,結(jié)果可能是:
| 2 | jack | 78 |
| 1 | tom | 45 |
| 3 | tom | 34 |
排序了,但是沒有去重
SQL2
那么我們加上去重:
select distinct name from score order by score desc limit 5;首先第一點(diǎn)是這個(gè)sql未必能執(zhí)行。在一些數(shù)據(jù)庫版本,這個(gè)sql可以被執(zhí)行,在一些版本則會(huì)提示你order by的字段必須在distinct中存在(見SQL3)。
但是即使能執(zhí)行,這個(gè)sql也得不到預(yù)期結(jié)果。原因是distinct優(yōu)先于order by 被數(shù)據(jù)庫執(zhí)行。
在執(zhí)行distinct name的時(shí)候,如上文中的數(shù)據(jù)。是取id=1的數(shù)據(jù),還是id=3的數(shù)據(jù)呢?其實(shí)這是數(shù)據(jù)庫自行決定的。因此,可能會(huì)不正確選擇數(shù)據(jù)。
比如真的執(zhí)行這個(gè)sql,可能去重的結(jié)果是:
| 2 | jack | 78 |
| 3 | tom | 34 |
然后再執(zhí)行一個(gè)order by,就會(huì)認(rèn)為第一名是jack78分,第二名是tom34分。然而其實(shí)tom應(yīng)該是45分,這個(gè)45分就在數(shù)據(jù)庫執(zhí)行distinct的時(shí)候被錯(cuò)誤的丟棄了,畢竟先執(zhí)行distinct的時(shí)候不知道你到底要哪個(gè)數(shù)據(jù)。
SQL3
那么我們把score加入select中呢?
select distinct name, score from score order by score desc limit 5;很明顯,這樣寫的執(zhí)行結(jié)果和我們預(yù)期不符。因?yàn)槿绻麑?#xff1a;distinct name,score實(shí)際上是對(duì)name和score一起去重。比如name都是jack,score都是45。那么這行就會(huì)被去掉。
但是問題是正因?yàn)榘裺core當(dāng)做去重的條件了。所以對(duì)于同名的人,比如都叫tom,會(huì)因?yàn)槠溆袃蓚€(gè)分?jǐn)?shù),導(dǎo)致不能被去重,從而保留兩行記錄。結(jié)果就是好像沒有去重。
SQL4
那我不用distinct,用group by進(jìn)行去重可以嗎?
select name from score group byname order by score desc limit 5;也不行,因?yàn)樵趃roup by的時(shí)候,數(shù)據(jù)庫還是不知道對(duì)兩行name一樣的數(shù)據(jù),究竟應(yīng)該留下哪一行。
SQL5
正確的寫法:
select name from score group byname order by max(score) desc limit 5;這樣寫,在執(zhí)行g(shù)roup by的時(shí)候,數(shù)據(jù)庫就知道要保留score最大的那一行了。
轉(zhuǎn)載于:https://www.cnblogs.com/dsj2016/p/10679366.html
總結(jié)
以上是生活随笔為你收集整理的sql如何先排序再去重的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你知道自己执行的是哪个jre吗?
- 下一篇: 【NLP】选择目标序列:贪心搜索和Bea