【IT168 技術】不少時候,咱們都須要清除結果集中的重複內容。爲了解決這個問題,一個辦法是在選擇語句中加入關鍵字 distinct。該關鍵字的做用是讓查詢引擎清楚重複內容,以便獲得一個無重複記錄的結果集。也許您還不知道,實際上group by子句也可用來刪除重複的內容, 本文將爲讀者介紹二者之間的不一樣之處,以及它們是如何生成理想的結果集的。express
1、關鍵字Distinct和Distinctrow函數
關鍵字distinct通常直接跟在查詢語句中SELECT的後面,替換可選的關鍵字all,而關鍵字all是默認的。Distinctrow是distinct的別名,它產生的效果與distinct是完成同樣的:ui
SELECT [ALL | DISTINCT | DISTINCTROW ]
select_expr
[FROM table_references
[WHERE where_condition]spa
爲了說明這些關鍵字的用法,咱們如下表中的數據爲例來進行說明。其中,該表含有一些水果名稱及其對應的顏色:3d
如下查詢將從上表中檢索全部水果的名稱,並按字母順序將其列出:blog
SELECT name
FROM fruits;排序
因爲沒有附帶顏色信息,因此每種水果品種的是重複的:開發
如今,讓咱們使用關鍵字distinct再查詢一次,看看結果如何:it
SELECT DISTINCT name
FROM fruits;io
不出所料,因爲附帶了水果的顏色信息,因此每種水果的名稱只出現了一次:
2、重複數據的取捨
有時候,是不能使用關鍵字distinct的,由於刪除複製的數據會致使錯誤的結果。請考慮下列情形:
客戶想要生成一張職工表,以便進行某些資料統計。 爲此,咱們可使用下列命令:
SELECT name,
gender,
salary
FROM employees
ORDER BY name;
奇怪的是,結果中出現了重複的「Kristen Ruegg」:
客戶說,他們不但願出現重複,因此開發人員在SELECT語句中加入了關鍵字distinct。 好了,這會可以知足客戶的要求了,可是問題也隨之而來了,由於公司確實有兩個重名的員工。因此,添加關鍵字distinct刪除了一個有效的記錄,所以得 到的結果實際上錯誤的。咱們能夠經過emp_id_number來確認一下,的確有兩名員工都叫Kristen Rueggs:
SELECT name,
gender,
salary,
emp_id_number
FROM employees
ORDER BY name;
下面是出現問題的數據,它們的emp_id_numbers都是惟一的:
上面的情形告訴咱們:使用關鍵字distinct的時候,要確保不會無心中刪除有效數據!
3、關鍵字Distinct與Group By的區別
使用distinct與不使用聚合功能狀況下對全選全部欄數據進行分組的邏輯效果是同樣的。對於這樣的查詢,group by命令只是生產了一列分組後的值。在顯示某欄並對齊分組的時候,該查詢會給出該欄中不一樣的值。然而,在顯示多欄並對它們進行分組的時候,該查詢會給出每 欄中的值的不一樣的組和。例如,如下查詢生成的結果與第一個SELECT distinct命令的結果徹底同樣:
SELECT name
FROM fruits
GROUP BY name;
一樣地,如下語句生成的結果,與咱們的SELECT distinct語句在員工表上生成的結果也徹底同樣:
SELECT name,
gender,
salary
FROM employees
GROUP BY name;
關鍵字distinct和group by的區別在於,group by子句會對數據記錄進行排序。所以:
SELECT name,
gender,
salary
FROM employees
GROUP BY name;
或者:
SELECT DISTINCT name,
gender,
salary
FROM employees
ORDER BY name;
4、統計重複的數據
關鍵字Distinct能夠用於COUNT()函數,來統計一欄中包含多少不一樣的值。COUNT ( distinct expression)將統計給定表達式在不一樣的非零值的數量。該表達式能夠是要統計其中不一樣的非零值的數量的欄名。
下面是表employee中的全部數據:
對name字段應用Count distinct函數會獲得六個不一樣的名稱:
SELECT Count(DISTINCT name)
FROM employees;
固然,也能夠給出一列用逗號分隔的表達式。倘若這樣,COUNT()將返回非空值的不一樣組合數目。如下查詢將統計哪些姓名和工資都非NULL的不一樣記錄的數目。
SELECT Count (DISTINCT name, salary)
FROM employees;
咱們還可使用group by子句計算每組中重複數據的數量。下面的查詢將用來統計不一樣部門中重名的狀況:
SELECT dept_id,
COUNT(*) - COUNT(DISTINCT name) AS 'duplicate names'
FROM employees
GROUP BY dept_id;
這些查詢能夠幫助咱們瞭解重複程度,可是,卻沒法告訴咱們重複的是哪些值。爲了弄清楚表employees中哪些名稱是複製的,咱們可使用下列查詢來顯示非惟一值,以及重複次數:
SELECT dept_id,
name,
count(name) as name_count
FROM employees
GROUP BY name,
dept_id;
咱們這裏僅對重複數據感興趣,因此使用HAVING子句將其餘數據所有過濾掉:
SELECT dept_id,
name,
count(name) as name_count
FROM employees
GROUP BY name,
dept_id
HAVING name_count > 1;
如今,咱們能夠知道哪些名稱是重複的,以及它們的重複次數:
5、顯示重複數據中每組最小或者最大值
就像在上面的例子中看到的那樣,group by子句會導致對字段列表中的每一個惟一值應用聚合函數。應該注意,沒有放進group by字段清單中的欄與被聚合的值沒必要放在同一行。這裏給出一個例子,如下查詢顯示每一個部門中的最高工資:
SELECT dept_id,
name,
gender,
max(salary) as max_salary
FROM employees
GROUP BY dept_id;
咱們還想要顯示拿最高工資的那些人的有關信息。然而,返回的結果確是:
問題在於,工資是惟一被聚合的欄,由於Max()聚合函數只被用於它。所以,顯示的是各個group by字段中遇到的第一個name和gender值。 經過查看這個表您會發現,雖然Ralph Teller是1號部門的惟一員工,可是隻有Jon Simpson拿到了$4500。咱們知道,應該顯示Peter Jonson,可是查詢引擎選擇了遇到的dept_id爲2的第一個名稱和性別。
解決方案是,將GROUP_BY結果與原始表進行合併。在這裏,咱們只有一個字段,即salary:
SELECT emp2.dept_id,
emp1.name,
emp1.gender,
emp2.max_salary
FROM (
SELECT dept_id,
Max(salary) as max_salary
FROM employees
GROUP BY dept_id
) as emp2 JOIN employees as emp1 ON emp1.salary = emp2.max_salary
GROUP BY dept_id;
如今,name和gender字段屬於最高工資者:
6、小結
不少時候,咱們都須要清除結果集中的重複內容。爲了解決這個問題,一個辦法是在選擇語句中加入關鍵字distinct。該關鍵字的做用是讓查詢引擎清楚 重複內容,以便獲得一個無重複記錄的結果集。也許您還不知道,實際上group by子句也可用來刪除重複的內容, 本文爲讀者介紹了二者之間的不一樣之處,以及它們是如何生成理想的結果集的。固然,咱們還可使用工做單元表和動態SQL刪除結果集中的重複數據。有機會我 們將在後文中專門加以講解。