SQL數(shù)據(jù)去重的七種方法小結(jié)
在平時工作中,使用SQL語句進(jìn)行數(shù)據(jù)去重的場景非常多。
今天主要分享幾種數(shù)據(jù)去重的SQL寫法。
假如有一張student表,結(jié)構(gòu)如下:
create table student( id int, name varchar(50), age int, address varchar(100) );
表中的數(shù)據(jù)如下:
方法一:使用DISTINCT關(guān)鍵字進(jìn)行去重
在使用DISTINCT關(guān)鍵字去重時,后面跟上去重的字段即可。
比如,取出student表中,不重復(fù)的address有哪些,可以使用如下SQL語句:
select distinct address from student;
返回結(jié)果如下:
這種方法,最大的優(yōu)點(diǎn)是使用起來比較簡單。
但也有一個比較大的缺點(diǎn),就是最終返回的結(jié)果集中的字段最多只包含去重的字段。也就是說,在上面的SQL語句中,使用address字段進(jìn)行去重,最終的結(jié)果,也最多只能返回address一個字段。
如果想以address字段去重,并且同時返回其他字段,DISTINCT是做不到的。
方法二:使用GROUP BY關(guān)鍵字進(jìn)行去重
與DISTINCT關(guān)鍵字一樣,GROUP BY關(guān)鍵字,也是標(biāo)準(zhǔn)SQL支持的常用的去重方法。它可以在去重的同時,同步返回其他字段的信息。
還是以對address字段進(jìn)行去重為例,其他字段可以使用聚合函數(shù)根據(jù)需要進(jìn)行獲取:
select min(id), max(name), max(age), address from student group by address;
返回結(jié)果如下:
在上面的語句中,不僅對address字段進(jìn)行了去重,也同時返回了id、name、age字段的信息。
在這一點(diǎn)上,比DISTINCT要好用很多。
不過,仔細(xì)一看,好像總是覺得哪里不對勁。
id=1的學(xué)生,應(yīng)該叫周俊廷,而在上面的返回結(jié)果中卻是楊蕭語,返回的age字段,也有同樣的問題。
也就是說,在返回的結(jié)果中,同一行的id、name、age,可能并不是同一個學(xué)生的,這就導(dǎo)致看起來數(shù)據(jù)有些混亂。
如果對數(shù)據(jù)的一致性有要求,可以使用下面的第三種方法。
方法三:使用窗口函數(shù)進(jìn)行去重
窗口函數(shù)有好幾種,使用起來大同小異,這里只介紹ROW_NUMBER() over(partition by ... order by ...)。
select id,name,age,address from ( select id,name,age,address, row_number() over( partition by address order by id asc ) as rn from student )a where a.rn = 1;
ROW_NUMBER()窗口函數(shù)的原理是,先對數(shù)據(jù)按照partition by的字段進(jìn)行分組,然后以order by的字段在各個分組內(nèi)進(jìn)行排序,序號從1開始遞增。
上面的SQL返回的結(jié)果為:
這個返回結(jié)果,就完美多了。
但是,需要注意的是,有些數(shù)據(jù)庫是不支持窗口函數(shù)的。像低版本的MySQL數(shù)據(jù)庫中就無法使用。
方法四:使用IN去重
這種方法的關(guān)鍵在于,找到一組不重復(fù)的數(shù)據(jù)的特征,然后以這個特征來取數(shù)據(jù)。
比如:按address來去重,如果數(shù)據(jù)有重復(fù),取id最大的那條。
select * from student where id in ( select max(id) from student group by address );
返回結(jié)果如下:
當(dāng)然,也可以取id最小的那條,將上面語句中的max改成min就可以了。
這種方法適合表里有一個數(shù)據(jù)不重復(fù)的字段(如上面SQL中的id字段)的情況。
如果表中不存在這樣一個字段,這種方法就不再適用了。但有些數(shù)據(jù)庫,天生自帶了類似的字段可以使用。
比如,在ORACLE數(shù)據(jù)庫中,可以使用ROWID替代上面SQL中的id字段。當(dāng)然僅限于ORACLE數(shù)據(jù)庫:
select * from student where rowid in ( select max(rowid) from student group by address );
方法五:使用NOT EXISTS去重
與方法四的思路類似,使用NOT EXISTS也可以實(shí)現(xiàn)同樣的效果。
select * from student a where not exists( select 1 from student b where a.address = b.address and a.id > b.id );
返回結(jié)果如下:
方法六:使用ALL關(guān)鍵字
在MySQL數(shù)據(jù)庫中,有一個特殊的操作符ALL,這是一個集合操作符,表示子數(shù)據(jù)集中的所有數(shù)據(jù)都滿足某一個條件。
select * from student a where a.id <= ALL( select b.id from student b where a.address = b.address );
返回結(jié)果如下:
在上面的SQL中,ALL操作符的意思是說,a.id字段要<=ALL操作符括號里查詢出來的所有值。
這種方法的核心思路與方法四是類似的。
方法七:使用INNER JOIN + GROUP BY關(guān)鍵字
這種方法的核心思路,也與方法四是類似的。
select a.* from student a inner join student b on a.address = b.address and a.id >= b.id group by a.id,a.name,a.age,a.address having count(*)=1;
返回結(jié)果如下:
上面介紹了7種數(shù)據(jù)去重的方法,你知道幾種?
到此這篇關(guān)于SQL數(shù)據(jù)去重的七種方法小結(jié)的文章就介紹到這了,更多相關(guān)SQL數(shù)據(jù)去重內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何恢復(fù)SQL Server 2000損壞的數(shù)據(jù)庫文件
在現(xiàn)實(shí)情況中由于硬件和軟件的原因可能導(dǎo)致數(shù)據(jù)庫文件損壞,那么損壞的數(shù)據(jù)庫文件有沒有辦法修復(fù)呢?下面講講如何恢復(fù)SQL Server 2000損壞的數(shù)據(jù)庫文件2014-01-01SQL語句實(shí)現(xiàn)查詢并自動創(chuàng)建Missing Index
這篇文章主要介紹了SQL語句實(shí)現(xiàn)查詢并自動創(chuàng)建Missing Index,本文直接給出SQL實(shí)現(xiàn)腳本,需要的朋友可以參考下2015-07-07SQLServer實(shí)現(xiàn)Ungroup操作的示例代碼
本文主要介紹了SQLServer實(shí)現(xiàn)Ungroup操作的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07一次SQL調(diào)優(yōu)數(shù)據(jù)庫性能問題后的過程(300W)
對單表超過300w+數(shù)據(jù)的Web應(yīng)用程序進(jìn)行測試后發(fā)現(xiàn)了一些功能、性能問題,采取了以下辦法來進(jìn)行調(diào)整2010-03-03MSSQL數(shù)據(jù)庫獲取TEXT字段的內(nèi)容長度
SQL Server數(shù)據(jù)庫如何獲取TEXT字段的內(nèi)容長度呢?本文我們就來介紹一下2013-03-03