天天看點

sql去重複操作詳解SQL中distinct的用法

在表中,可能會包含重複值。這并不成問題,不過,有時您也許希望僅僅列出不同(distinct)的值。關鍵詞 distinct用于傳回唯一不同的值。

表A:

sql去重複操作詳解SQL中distinct的用法

表B:

sql去重複操作詳解SQL中distinct的用法

1.作用于單列

select distinct name from A      

執行後結果如下:

sql去重複操作詳解SQL中distinct的用法

2.作用于多列

示例2.1

select distinct name, id from A      

執行後結果如下:

sql去重複操作詳解SQL中distinct的用法

實際上是根據name和id兩個字段來去重的,這種方式Access和SQL Server同時支援。

示例2.2

select distinct xing, ming from B      

傳回如下結果:

sql去重複操作詳解SQL中distinct的用法

傳回的結果為兩行,這說明distinct并非是對xing和ming兩列“字元串拼接”後再去重的,而是分别作用于了xing和ming列。

3.COUNT統計

select count(distinct name) from A;	  --表中name去重後的數目, SQL Server支援,而Access不支援      

count是不能統計多個字段的,下面的SQL在SQL Server和Access中都無法運作。

select count(distinct name, id) from A;      

若想使用,請使用嵌套查詢,如下:

select count(*) from (select distinct xing, name from B) AS M;      

4.distinct必須放在開頭

select id, distinct name from A;   --會提示錯誤,因為distinct必須放在開頭      

5.其他

distinct語句中select顯示的字段隻能是distinct指定的字段,其他字段是不可能出現的。例如,假如表A有“備注”列,如果想擷取distinc name,以及對應的“備注”字段,想直接通過distinct是不可能實作的。但可以通過其他方法實作關于SQL Server将一列的多行内容拼接成一行的問題讨論

distinct這個關鍵字用來過濾掉多餘的重複記錄隻保留一條,但往往隻用它來傳回不重複記錄的條數,而不是用它來傳回不重記錄的所有值。其原因是distinct隻有用二重循環查詢來解決,而這樣對于一個資料量非常大的站來說,無疑是會直接影響到效率的。

下面先來看看例子:

table表

字段1     字段2

   id        name

   1           a

   2           b

   3           c

   4           c

   5           b

庫結構大概這樣,這隻是一個簡單的例子,實際情況會複雜得多。

比如我想用一條語句查詢得到name不重複的所有資料,那就必須

使用distinct去掉多餘的重複記錄。

select distinct name from table

得到的結果是: 

---------- 

name

   a

   c

好像達到效果了,可是,我想要得到的是id值呢?改一下查詢語句吧:

select distinct name, id from table

結果會是:

---------- 

id name

   1 a

   2 b

   3 c

   4 c

   5 b

distinct怎麼沒起作用?作用是起了的,不過他同時作用了兩個

字段,也就是必須得id與name都相同的才會被排除

我們再改改查詢語句:

select id, distinct name from table

很遺憾,除了錯誤資訊你什麼也得不到,distinct必須放在開頭。難到不能把distinct放到where條件裡?能,照樣報錯。

--------------------------------------------------------

下面方法可行:

select *, count(distinct name) from table group by name

結果:

   id name count(distinct name)

   1 a 1

   2 b 1

   3 c 1

最後一項是多餘的,不用管就行了,目的達到

group by 必須放在 order by 和 limit之前,不然會報錯

distinct這個關鍵字來過濾掉多餘的重複記錄隻保留一條,但往往隻用它來傳回不重複記錄的條數,而不是用它來傳回不重記錄的所有值。其原因是distinct隻能傳回它的目标字段,而無法傳回其它字段,接下來通過本篇文章給大家分享SQL中distinct的用法,需要的朋友可以參考下

在使用mysql時,有時需要查詢出某個字段不重複的記錄,雖然mysql提供有distinct這個關鍵字來過濾掉多餘的重複記錄隻保留一條,但往往隻 用它來傳回不重複記錄的條數,而不是用它來傳回不重記錄的所有值。其原因是distinct隻能傳回它的目标字段,而無法傳回其它字段,這個問題讓我困擾很久,用distinct不能解決的話,我隻有用二重循環查詢來解決,而這樣對于一個資料量非常大的站來說,無疑是會直接影響到效率的,是以浪費了我大量時間。

在表中,可能會包含重複值。這并不成問題,不過,有時您也許希望僅僅列出不同(distinct)的值。關鍵詞 distinct用于傳回唯一不同的值。

表A:

sql去重複操作詳解SQL中distinct的用法

示例1

複制代碼 代碼如下:

select distinct name from A

執行後結果如下:

示例2

複制代碼 代碼如下:

select distinct name, id from A

執行後結果如下:

實際上是根據“name+id”來去重,distinct同時作用在了name和id上,這種方式Access和SQL Server同時支援。

示例3:統計

複制代碼 代碼如下:

select count(distinct name) from A;   --表中name去重後的數目, SQL Server支援,而Access不支援

select count(distinct name, id) from A;   --SQL Server和Access都不支援

示例4

複制代碼 代碼如下:

select id, distinct name from A;   --會提示錯誤,因為distinct必須放在開頭

在使用mysql時,有時需要查詢出某個字段不重複的記錄,這時可以使用mysql提供的distinct這個關鍵字來過濾重複的記錄,但是實際中我們往往用distinct來傳回不重複字段的條數(count(distinct id)),其原因是distinct隻能傳回他的目标字段,而無法傳回其他字段,例如有如下表user:

sql去重複操作詳解SQL中distinct的用法

用distinct來傳回不重複的使用者名:select distinct name from user;,結果為:

sql去重複操作詳解SQL中distinct的用法

這樣隻把不重複的使用者名查詢出來了,但是使用者的id,并沒有被查詢出來:select distinct name,id from user;,這樣的結果為:

sql去重複操作詳解SQL中distinct的用法

distinct name,id 這樣的mysql 會認為要過濾掉name和id兩個字段都重複的記錄,如果sql這樣寫:select id,distinct name from user,這樣mysql會報錯,因為distinct必須放在要查詢字段的開頭。

是以一般distinct用來查詢不重複記錄的條數。

如果要查詢不重複的記錄,有時候可以用group by :

select id,name from user group by name;

1 前言

在咱們編寫 SQL 語句操作資料庫中的資料的時候,有可能會遇到一些不太爽的問題,例如對于同一字段擁有相同名稱的記錄,我們隻需要顯示一條,但實際上資料庫中可能含有多條擁有相同名稱的記錄,進而在檢索的時候,顯示多條記錄,這就有違咱們的初衷啦!是以,為了避免這種情況的發生,咱們就需要進行“去重”處理啦,那麼何為“去重”呢?說白了,就是對同一字段讓擁有相同内容的記錄隻顯示一條記錄。

那麼,如何實作“去重”的功能呢?對此,咱們有兩種方式可以實作該功能。

  • 第一種,在編寫 select 語句的時候,添加 distinct 關鍵詞;
  • 第二種,在編寫 select 語句的時候,調用 row_number() over() 函數。

以上兩種方式都可以實作“去重”功能,那兩者之間有何異同呢?接下來,作者将給出詳細的說明。

2 distinct

在 SQL 中,關鍵字 distinct 用于傳回唯一不同的值。其文法格式為:

SELECT DISTINCT 列名稱 FROM 表名稱
           
  • 1

假設有一個表“CESHIDEMO”,包含兩個字段,分别 NAME 和 AGE,具體格式如下:

sql去重複操作詳解SQL中distinct的用法

觀察以上的表,咱們會發現:擁有相同 NAME 的記錄有兩條,擁有相同 AGE 的記錄有三條。如果咱們運作下面這條 SQL 語句,

  1. select name from PPPRDER.CESHIDEMO

  • 1
  • 2
  • 3
  • 4
  • 5

将會得到如下結果:

sql去重複操作詳解SQL中distinct的用法

觀察該結果,咱們會發現在以上的四條記錄中,包含兩條 NAME 值相同的記錄,即第 2 條記錄和第 3 條記錄的值都為“gavin”。那麼,如果咱們想讓擁有相同 NAME 的記錄隻顯示一條該如何實作呢?這時,就需要用到 distinct 關鍵字啦!接下來,運作如下 SQL 語句,

select distinct name from PPPRDER.CESHIDEMO
           
  • 1

将會得到如下結果:

sql去重複操作詳解SQL中distinct的用法

觀察該結果,顯然咱們的要求得到實作啦!但是,咱們不禁會想到,如果将 distinct 關鍵字同時作用在兩個字段上将會産生什麼效果呢?既然想到了,咱們就試試呗,運作如下 SQL 語句,

select distinct name, age from PPPRDER.CESHIDEMO
           
  • 1

得到的結果如下所示:

sql去重複操作詳解SQL中distinct的用法

觀察該結果,哎呀,貌似沒有作用啊?她将全部的記錄都顯示出來了啊!其中 NAME 值相同的記錄有兩條,AGE 值相同的記錄有三條,完全沒有變化啊!但事實上,結果就應該是這樣的。因為當 distinct 作用在多個字段的時候,她隻會将所有字段值都相同的記錄“去重”掉,顯然咱們“可憐”的四條記錄并不滿足該條件,是以 distinct 會認為上面四條記錄并不相同。空口無憑,接下來,咱們再向表“CESHIDEMO”中添加一條完全相同的記錄,驗證一下即可。添加一條記錄後的表如下所示:

sql去重複操作詳解SQL中distinct的用法

再運作如下的 SQL 語句,

select distinct name, age from PPPRDER.CESHIDEMO
           
  • 1

得到的結果如下所示:

sql去重複操作詳解SQL中distinct的用法

觀察該結果,完美的驗證了咱們上面的結論。

此外,有一點需要大家特别注意,即:關鍵字 distinct 隻能放在 SQL 語句中所有字段的最前面才能起作用,如果放錯位置,SQL 不會報錯,但也不會起到任何效果。

3 row_number() over()

在 SQL Server 資料庫中,為咱們提供了一個函數 row_number() 用于給資料庫表中的記錄進行标号,在使用的時候,其後還跟着一個函數 over(),而函數 over() 的作用是将表中的記錄進行分組和排序。兩者使用的文法為:

ROW_NUMBER() OVER(PARTITION BY COLUMN1 ORDER BY COLUMN2)
           
  • 1

意為:将表中的記錄按字段 COLUMN1進行分組,按字段 COLUMN2 進行排序,其中

  • PARTITION BY:表示分組
  • ORDER BY:表示排序

接下來,咱們還用表“CESHIDEMO”中的資料進行測試。首先,給出沒有使用 row_number() over() 函數時查詢的結果,如下所示:

sql去重複操作詳解SQL中distinct的用法

然後,運作如下 SQL 語句,

select  PPPRDER.CESHIDEMO.*, row_number() over(partition by age order by name desc) from PPPRDER.CESHIDEMO
           
  • 1

得到的結果如下所示:

sql去重複操作詳解SQL中distinct的用法

從上面的結果可以看出,其在原表的基礎上,多了一列标有數字排序的列。那麼反過來分析咱們運作的 SQL 語句,發現其确實按字段 AGE 的值進行分組了,也按字段 NAME 的值進行排序啦!是以,函數的功能得到了驗證。

接下來,咱們就研究如何用 row_number() over() 函數實作“去重”的功能。通過觀察上面的結果,咱們可以發現,如果以 NAME 分組,以 AGE 排序,然後再取每組的第一個記錄或許就可以實作“去重”的功能啊!那麼試試看,運作如下 SQL 語句,

  1. select * from

  2. (select PPPRDER.CESHIDEMO.*, row_number() over(partition by name order by age desc) rn from PPPRDER.CESHIDEMO)

  3. where rn = 1

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

運作後,得到的結果如下所示:

sql去重複操作詳解SQL中distinct的用法

觀察以上的結果,我們發現,哎呀,資料“去重”的功能一不小心就被咱們實作了啊!不過很遺憾,如果咱們細心的話,會發現一個很不爽的事情,那就是在執行以上 SQL 語句進行“去重”的時候,有一條 NAME 值為“gavin”、AGE 值為“18”的記錄被過濾掉了,但是在現實生活會中,同名不同年齡的事情太正常了

繼續閱讀