1. 程式人生 > >SQL中distinct 和 row_number() over() 的區別及用法

SQL中distinct 和 row_number() over() 的區別及用法

1 前言

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

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

第一種,在編寫 select 語句的時候,新增 distinct 關鍵詞;

第二種,在編寫 select 語句的時候,呼叫 row_number() over() 函式。

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

2 distinct

在 SQL 中,關鍵字distinct 用於返回唯一不同的值。其語法格式為:

SELECT DISTINCT 列名稱 FROM 表名稱

假設有一個表“Student”,包含兩個欄位,分別 NAME 和 AGE,具體格式如下:

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

/**

* 其中 PPPRDER 為 Schema 的名字,即表Student 在 PPPRDER 中

*/

select name from Student

將會得到如下結果:

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

select distinct name from Student

將會得到如下結果:

觀察該結果,顯然咱們的要求得到實現啦!但是,咱們不禁會想到,如果將distinct 關鍵字同時作用在兩個欄位上將會產生什麼效果呢?既然想到了,咱們就試試唄,執行如下 SQL 語句,

select distinct name, age from Student

得到的結果如下所示:

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

再執行如下的 SQL 語句,

select distinct name, age from Student

得到的結果如下所示:

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

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

3 row_number() over()

在 SQL Server 資料庫中,為咱們提供了一個函式 row_number() 用於給資料庫表中的記錄進行標號,在使用的時候,其後還跟著一個函式 over(),而函式 over() 的作用是將表中的記錄進行分組和排序。兩者使用的語法為:

ROW_NUMBER() OVER(PARTITION BY COLUMN1ORDER BY COLUMN2)

意為:將表中的記錄按欄位 COLUMN1進行分組,按欄位 COLUMN2 進行排序,其中

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

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

然後,執行如下 SQL 語句,

select Student.*, row_number()over(partition by age order by name desc) from Student

得到的結果如下所示:

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

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

/*

* 其中 rn 表示最後新增的那一列

*/

select * from

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

where rn = 1

執行後,得到的結果如下所示:

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

4 總結

通過閱讀及實踐以上內容,咱們已經知道了,無論是用關鍵字 distinct 還是用函式 row_number() over() 都可以實現資料“去重”的功能。但是在實現使用的過程中,咱們要特別注意兩者的用法特點以及區別。

在使用關鍵字 distinct 的時候,咱們要知道其作用於單個欄位和多個欄位的時候是有區別的,作用於單個欄位時,其“去重”的是表中所有該欄位值重複的資料;作用於多個欄位的時候,其“去重”的表中所有欄位(即distinct 具體作用的多個欄位)值都相同的資料。

在使用函式 row_number() over() 的時候,其是按先分組排序後,再取出每組的第一條記錄來進行“去重”的(在本篇博文中如此)。當然,在此處咱們還可以通過不同的限制條件來進行“去重”,具體如何實現,就需要大家自己去動腦思考啦!

1 前言

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

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

第一種,在編寫 select 語句的時候,新增 distinct 關鍵詞;

第二種,在編寫 select 語句的時候,呼叫 row_number() over() 函式。

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

2 distinct

在 SQL 中,關鍵字distinct 用於返回唯一不同的值。其語法格式為:

SELECT DISTINCT 列名稱 FROM 表名稱

假設有一個表“Student”,包含兩個欄位,分別 NAME 和 AGE,具體格式如下:

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

/**

* 其中 PPPRDER 為 Schema 的名字,即表Student 在 PPPRDER 中

*/

select name from Student

將會得到如下結果:

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

select distinct name from Student

將會得到如下結果:

觀察該結果,顯然咱們的要求得到實現啦!但是,咱們不禁會想到,如果將distinct 關鍵字同時作用在兩個欄位上將會產生什麼效果呢?既然想到了,咱們就試試唄,執行如下 SQL 語句,

select distinct name, age from Student

得到的結果如下所示:

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

再執行如下的 SQL 語句,

select distinct name, age from Student

得到的結果如下所示:

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

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

3 row_number() over()

在 SQL Server 資料庫中,為咱們提供了一個函式 row_number() 用於給資料庫表中的記錄進行標號,在使用的時候,其後還跟著一個函式 over(),而函式 over() 的作用是將表中的記錄進行分組和排序。兩者使用的語法為:

ROW_NUMBER() OVER(PARTITION BY COLUMN1ORDER BY COLUMN2)

意為:將表中的記錄按欄位 COLUMN1進行分組,按欄位 COLUMN2 進行排序,其中

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

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

然後,執行如下 SQL 語句,

select Student.*, row_number()over(partition by age order by name desc) from Student

得到的結果如下所示:

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

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

/*

* 其中 rn 表示最後新增的那一列

*/

select * from

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

where rn = 1

執行後,得到的結果如下所示:

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

4 總結

通過閱讀及實踐以上內容,咱們已經知道了,無論是用關鍵字 distinct 還是用函式 row_number() over() 都可以實現資料“去重”的功能。但是在實現使用的過程中,咱們要特別注意兩者的用法特點以及區別。

在使用關鍵字 distinct 的時候,咱們要知道其作用於單個欄位和多個欄位的時候是有區別的,作用於單個欄位時,其“去重”的是表中所有該欄位值重複的資料;作用於多個欄位的時候,其“去重”的表中所有欄位(即distinct 具體作用的多個欄位)值都相同的資料。

在使用函式 row_number() over() 的時候,其是按先分組排序後,再取出每組的第一條記錄來進行“去重”的(在本篇博文中如此)。當然,在此處咱們還可以通過不同的限制條件來進行“去重”,具體如何實現,就需要大家自己去動腦思考啦!