SQL中distinct 和 row_number() over() 的區(qū)別及用法
1 前言
在咱們編寫 SQL 語句操作數(shù)據(jù)庫中的數(shù)據(jù)的時(shí)候,有可能會(huì)遇到一些不太爽的問題,例如對(duì)于同一字段擁有相同名稱的記錄,我們只需要顯示一條,但實(shí)際上數(shù)據(jù)庫中可能含有多條擁有相同名稱的記錄,從而在檢索的時(shí)候,顯示多條記錄,這就有違咱們的初衷啦!因此,為了避免這種情況的發(fā)生,咱們就需要進(jìn)行“去重”處理啦,那么何為“去重”呢?說白了,就是對(duì)同一字段讓擁有相同內(nèi)容的記錄只顯示一條記錄。
那么,如何實(shí)現(xiàn)“去重”的功能呢?對(duì)此,咱們有兩種方式可以實(shí)現(xiàn)該功能。
第一種,在編寫 select 語句的時(shí)候,添加 distinct 關(guān)鍵詞;
第二種,在編寫 select 語句的時(shí)候,調(diào)用 row_number() over() 函數(shù)。
以上兩種方式都可以實(shí)現(xiàn)“去重”功能,那兩者之間有何異同呢?接下來,作者將給出詳細(xì)的說明。
2 distinct
在 SQL 中,關(guān)鍵字 distinct 用于返回唯一不同的值。其語法格式為:
SELECT DISTINCT 列名稱 FROM 表名稱
假設(shè)有一個(gè)表“CESHIDEMO”,包含兩個(gè)字段,分別 NAME 和 AGE,具體格式如下:
觀察以上的表,咱們會(huì)發(fā)現(xiàn):擁有相同 NAME 的記錄有兩條,擁有相同 AGE 的記錄有三條。如果咱們運(yùn)行下面這條 SQL 語句,
/** * 其中 PPPRDER 為 Schema 的名字,即表 CESHIDEMO 在 PPPRDER 中 */ select name from PPPRDER.CESHIDEMO
將會(huì)得到如下結(jié)果:
觀察該結(jié)果,咱們會(huì)發(fā)現(xiàn)在以上的四條記錄中,包含兩條 NAME 值相同的記錄,即第 2 條記錄和第 3 條記錄的值都為“gavin”。那么,如果咱們想讓擁有相同 NAME 的記錄只顯示一條該如何實(shí)現(xiàn)呢?這時(shí),就需要用到 distinct 關(guān)鍵字啦!接下來,運(yùn)行如下 SQL 語句,
select distinct name from PPPRDER.CESHIDEMO
將會(huì)得到如下結(jié)果:
觀察該結(jié)果,顯然咱們的要求得到實(shí)現(xiàn)啦!但是,咱們不禁會(huì)想到,如果將 distinct 關(guān)鍵字同時(shí)作用在兩個(gè)字段上將會(huì)產(chǎn)生什么效果呢?既然想到了,咱們就試試唄,運(yùn)行如下 SQL 語句,
select distinct name, age from PPPRDER.CESHIDEMO
得到的結(jié)果如下所示:
觀察該結(jié)果,哎呀,貌似沒有作用?。克龑⑷康挠涗浂硷@示出來了?。∑渲?NAME 值相同的記錄有兩條,AGE 值相同的記錄有三條,完全沒有變化?。〉聦?shí)上,結(jié)果就應(yīng)該是這樣的。因?yàn)?strong>當(dāng) distinct 作用在多個(gè)字段的時(shí)候,她只會(huì)將所有字段值都相同的記錄“去重”掉,顯然咱們“可憐”的四條記錄并不滿足該條件,因此 distinct 會(huì)認(rèn)為上面四條記錄并不相同??湛跓o憑,接下來,咱們?cè)傧虮怼癈ESHIDEMO”中添加一條完全相同的記錄,驗(yàn)證一下即可。添加一條記錄后的表如下所示:
再運(yùn)行如下的 SQL 語句,
select distinct name, age from PPPRDER.CESHIDEMO
得到的結(jié)果如下所示:
觀察該結(jié)果,完美的驗(yàn)證了咱們上面的結(jié)論。
此外,有一點(diǎn)需要大家特別注意,即:關(guān)鍵字 distinct 只能放在 SQL 語句中所有字段的最前面才能起作用,如果放錯(cuò)位置,SQL 不會(huì)報(bào)錯(cuò),但也不會(huì)起到任何效果。
3 row_number() over()
在 SQL Server 數(shù)據(jù)庫中,為咱們提供了一個(gè)函數(shù) row_number() 用于給數(shù)據(jù)庫表中的記錄進(jìn)行標(biāo)號(hào),在使用的時(shí)候,其后還跟著一個(gè)函數(shù) over(),而函數(shù) over() 的作用是將表中的記錄進(jìn)行分組和排序。兩者使用的語法為:
ROW_NUMBER() OVER(PARTITION BY COLUMN1 ORDER BY COLUMN2)
意為:將表中的記錄按字段 COLUMN1進(jìn)行分組,按字段 COLUMN2 進(jìn)行排序,其中
PARTITION BY:表示分組ORDER BY:表示排序
接下來,咱們還用表“CESHIDEMO”中的數(shù)據(jù)進(jìn)行測(cè)試。首先,給出沒有使用 row_number() over() 函數(shù)時(shí)查詢的結(jié)果,如下所示:
然后,運(yùn)行如下 SQL 語句,
select PPPRDER.CESHIDEMO.*, row_number() over(partition by age order by name desc) from PPPRDER.CESHIDEMO
得到的結(jié)果如下所示:
從上面的結(jié)果可以看出,其在原表的基礎(chǔ)上,多了一列標(biāo)有數(shù)字排序的列。那么反過來分析咱們運(yùn)行的 SQL 語句,發(fā)現(xiàn)其確實(shí)按字段 AGE 的值進(jìn)行分組了,也按字段 NAME 的值進(jìn)行排序啦!因此,函數(shù)的功能得到了驗(yàn)證。
接下來,咱們就研究如何用 row_number() over() 函數(shù)實(shí)現(xiàn)“去重”的功能。通過觀察上面的結(jié)果,咱們可以發(fā)現(xiàn),如果以 NAME 分組,以 AGE 排序,然后再取每組的第一個(gè)記錄或許就可以實(shí)現(xiàn)“去重”的功能??!那么試試看,運(yùn)行如下 SQL 語句,
/* * 其中 rn 表示最后添加的那一列 */ select * from (select PPPRDER.CESHIDEMO.*, row_number() over(partition by name order by age desc) rn from PPPRDER.CESHIDEMO) where rn = 1
運(yùn)行后,得到的結(jié)果如下所示:
觀察以上的結(jié)果,我們發(fā)現(xiàn),哎呀,數(shù)據(jù)“去重”的功能一不小心就被咱們實(shí)現(xiàn)了??!不過很遺憾,如果咱們細(xì)心的話,會(huì)發(fā)現(xiàn)一個(gè)很不爽的事情,那就是在執(zhí)行以上 SQL 語句進(jìn)行“去重”的時(shí)候,有一條 NAME 值為“gavin”、AGE 值為“18”的記錄被過濾掉了,但是在現(xiàn)實(shí)生活會(huì)中,同名不同年齡的事情太正常了。
4 總結(jié)
通過閱讀及實(shí)踐以上內(nèi)容,咱們已經(jīng)知道了,無論是用關(guān)鍵字 distinct 還是用函數(shù) row_number() over() 都可以實(shí)現(xiàn)數(shù)據(jù)“去重”的功能。但是在實(shí)現(xiàn)使用的過程中,咱們要特別注意兩者的用法特點(diǎn)以及區(qū)別。
在使用關(guān)鍵字 distinct 的時(shí)候,咱們要知道其作用于單個(gè)字段和多個(gè)字段的時(shí)候是有區(qū)別的,作用于單個(gè)字段時(shí),其“去重”的是表中所有該字段值重復(fù)的數(shù)據(jù);作用于多個(gè)字段的時(shí)候,其“去重”的表中所有字段(即 distinct 具體作用的多個(gè)字段)值都相同的數(shù)據(jù)。
在使用函數(shù) row_number() over() 的時(shí)候,其是按先分組排序后,再取出每組的第一條記錄來進(jìn)行“去重”的(在本篇博文中如此)。當(dāng)然,在此處咱們還可以通過不同的限制條件來進(jìn)行“去重”,具體如何實(shí)現(xiàn),就需要大家自己去動(dòng)腦思考啦!
最后,在本篇博文中,作者詳述了自己對(duì)用關(guān)鍵字 distinct 和函數(shù) row_number() over() 進(jìn)行數(shù)據(jù)“去重”的一些認(rèn)識(shí),希望以上的內(nèi)容能夠?qū)Υ蠹矣兴鶐椭?/p>
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
- 使用row_number()實(shí)現(xiàn)分頁實(shí)例
- oracle中rownum和row_number()
- 利用ROW_NUMBER() OVER函數(shù)給SQL數(shù)據(jù)庫中每一條記錄分配行號(hào)的方法
- Mysql row number()排序函數(shù)的用法和注意
- MYSQL row_number()與over()函數(shù)用法詳解
- SQL使用ROW_NUMBER() OVER函數(shù)生成序列號(hào)
- MySQL中rank() over、dense_rank() over、row_number() over用法介紹
- SQL中row_number()?over(partition?by)的用法說明
- Row_number()函數(shù)用法小結(jié)
- 數(shù)據(jù)庫中row_number() 分組排序函數(shù)的具體使用
相關(guān)文章
利用explain排查分析慢sql的實(shí)戰(zhàn)案例
在日常工作中,我們會(huì)有時(shí)會(huì)開慢查詢?nèi)ビ涗浺恍﹫?zhí)行時(shí)間比較久的SQL語句,下面這篇文章主要給大家介紹了關(guān)于利用explan排查分析慢sql的相關(guān)資料,需要的朋友可以參考下2022-04-04MySQL數(shù)據(jù)表字段內(nèi)容的批量修改、清空、復(fù)制等更新命令
MySQL數(shù)據(jù)表字段內(nèi)容的批量修改、清空、復(fù)制等更新命令,需要的朋友可以參考下。2011-08-08Mysql使用on update current_timestamp問題
這篇文章主要介紹了Mysql使用on update current_timestamp問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03聽說mysql中的join很慢?是你用的姿勢(shì)不對(duì)吧
這篇文章主要介紹了聽說mysql中的join很慢?是你用的姿勢(shì)不對(duì)吧,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09idea連接mysql數(shù)據(jù)庫失敗的幾種解決方案
我們?cè)趯W(xué)習(xí)Mybatis時(shí)需要連接Mysql數(shù)據(jù)庫,使用IDEA無法連接mysql數(shù)據(jù)庫,下面這篇文章主要給大家介紹了關(guān)于idea連接mysql數(shù)據(jù)庫失敗的幾種解決方案,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06