本資料為產品崗位作為日常工作參考,語言口語化
At 2019/4/22 By David.Yang
排重查詢(使用DISTINCT運算符來消除結果集中的重複行)
針對現有業務數據進行查詢時,會有重複的數據記錄,
有時候我們需要進行排重的數據查詢,為了避免重複數據,
我們通常使用DISTINCT進行處理。
語法:
SELECT DISTINCT
column[,column...]
FROM
table_name
WHERE
where_conditions;
這個查詢語法我們在看完SELECT語法後應該比較熟悉了。
其中column可以是多個字段哦~
DISTINCT語句演示
為了進行數據演示,我們將學生表加入國家字段,代表各個學生的國際都是哪些。
不知道大家是否還記得怎麼對數據表進行字段新增的?
SQL
ALTER TABLE `students` ADD `nationality` varchar(20) COMMENT '國籍' AFTER `age`;
然後把數據補進去。
然後呢?
校長先生想看看今年的學生招收情況,這些學生都來自哪些國家?
我們教導主任周伯通,這可就難為了,
因為他知道,想要知道所有學生的國籍呢,
這個簡單啊,他會,
只要這麼做就行了
SQL
SELECT
nationality
FROM
students;
周伯通一看好開心呀~
看,學生來自五湖四海,大江南北啊,有南宋的,有西遼的,有西夏的,
看來俺們這學校聲譽不錯啊。
等等,咋是南宋、南宋一樣一樣的呢?
可是這不行啊,校長要的是生源地,怎麼還有重複的呢?
這可愁壞了教導主任周伯通。
怎麼才能去掉重複的呢?
這旁邊一看坐的誰啊?
老情敵一燈大師啊!
沒辦法,校長的任務還得幹,
沒什麼不好意思的,問吧
“額,那啥,一燈”
“當年是我不對啊,搶了你媳婦兒瑛姑”
“你都當和尚了,也就不計較了,咱進行個學術討論啊”
“訥啥,你看看我這校長給的統計生源的事兒,你給瞅一眼唄”
一燈答:“行”
“看老衲給你點撥一二”
一燈的SQL是這麼寫的
SQL
SELECT DISTINCT
nationality
FROM
students;
一燈“牛逼不,就一字兒”
“嗯… 嗯~”
以上,就說明了DISTINCT關鍵字是幹什麼的了,他成功的消除了重複項。
DISTINCT多列怎麼用
一燈曰“再給你開個光,瞅瞅多個列會有啥效果”
SQL
SELECT DISTINCT
nationality, gender
FROM
students;
結果集會告訴你南宋下的生源有男、女性別,
西夏就不同了,只有姑娘,沒有男娃兒。
以上假如我們還有學生的縣府數據,上邊的示例變通一下,
我們是不是就可以獲得國籍– 府縣了呢?
比如:
SELECT DISTINCT
nationality,州字段
FROM
students;
南宋– 京兆府
南宋– 延安府
南宋– 商州
南宋– 同州
南宋– 華州
…
如果不是有DISTINCT語句控制,你得到的數據將會是
南宋– 京兆府
南宋– 京兆府
南宋– 京兆府
…
南宋– 延安府
南宋– 延安府
南宋– 延安府
…
南宋– 商州
南宋– 商州
南宋– 商州
…
南宋– 同州
南宋– 華州
…
DISTINCT對NULL值的處理
我們再招一個洋學生,叫路易11,不設置他的國籍,
數據庫對應國籍為NULL,我們看看會是什麼結果?
SQL
SELECT DISTINCT nationality FROM students;
DISTINCT對NULL類型數據是不進行過濾的,
即返回結果集中會包含NULL的值。
那我們要排除NULL的空數據呢?
可以直接在WHERE條件中加以限制。
SQL
SELECTDISTINCTROW
nationality
FROM
students
WHERE
nationality IS NOT NULL;
注:後續過濾查詢會講解WHERE子句
DISTINCT對*值的處理
mysql> SELECT DISTINCT * FROM students;
這時候其實等價於:
SELECT DISTINCT
nationality,gender, xxx, xxx, xxx, …
FROM
students;
DISTINCT與LIMIT
我們前文提起過LIMIT,用來限制返回的數據記錄條數,
這裡也同樣可以使用。
SQL
SELECT DISTINCTROW
nationality
FROM
students
LIMIT 3;
注:後續過濾查詢會講解LIMIT子句
DISTINCT與GROUP BY子句比較
GROUP BY看字面意思聚合,分組,我們大概就能想到,
他與DISTINCT多少有點關係,或能做差不多的事情,
你別說,還真是。
比如我們要用GROUP BY來實現生源地統計,該怎麼做呢?
一燈大師會這麼做:
SQL
SELECT
nationality
FROM
students
GROUP BY
nationality;
一燈說“瞅見沒,一樣一樣的”
“不對呀,不是一樣一樣的撒,這不順序不太一樣麼?和尚”
確實,順序是不一樣。
一般來說,DISTINCT和GROUP
BY字句能幹差不多的事,
那我們要是給DISTINCT加個排序呢?
(別慌,排序我們後文會講的,現在留個印象日後好相處)
SQL
SELECT DISTINCT
nationality
FROM
students
ORDER BY
nationality;
DISTINCT與聚合函數的組合使用
SQL當中有一些聚合函數,比如SUM/COUNT/AVG等等,
他們可以用來與DISTINCT組合使用進行一些業務場景的查詢。
-- 統計班級性別的分佈情況
SQL
SELECT
gender, COUNT(DISTINCT number)
FROM
students
GROUP BY
gender;
因為學號是學生的標記,我們通過DISTINCT就可以排除重複學號數據,
在通過COUNT進行計數統計,
後然通過gender進行分組;
再比如統計學生年齡分佈,可以這麼寫:
SQL
SELECT
age, COUNT(DISTINCT number)
FROM
students
GROUP BY
age;
注:
此種場景不能脫離GROUP BY字句。
-- 統計學生最大年齡,並統計有多少人?
SQL
SELECT
max(age), COUNT(DISTINCT number)
FROM
students
WHERE
age = (SELECT max(age) FROM students);
當然你也可以加上條件進行查詢,
比如看來自西夏的學生最大年齡是多少,有多少人?
SQL
SELECT
nationality, max(age), COUNT(DISTINCTnumber)
FROM
students
WHERE
nationality = '西夏'
AND
age = (SELECT max(age) FROM studentsWHERE nationality = '西夏');
SQL解釋
ϒ以上在WHERE當中使用了子查詢,需要通過子查詢先算出最大年齡是多少,再進行外圍SQL的查詢。
所以你如果這麼寫,就會報錯
SQL ERROR
SELECT
max(age), COUNT(DISTINCT number)
FROM
students
WHERE
age = max(age);
錯誤提示:
為什麼呢?
聚集函數也叫列函數,它們都是基於整列數據進行計算的,
而where子句則是對數據行進行過濾的(這裡過濾是在一個記錄裡邊過濾的,基於"行"),
在篩選過程中依賴“基於已經篩選完畢的數據得出的計算結果”是一種悖論,
這是行不通的。
更簡單地說,因為聚集函數要對全列數據時行計算,
因而使用它的前提是:結果集已經確定!
而where子句還處於“確定”結果集的過程中,因而不能使用聚集函數。
ϒ如果你需要再進一步限定WHERE條件,那麼請再子查詢和WHERE條件內進行條件的操作
比如前面例子,我只想統計來自西夏的學生,
那麼你需要現統計出西夏學生的最大年齡,這個在子語句中實現,
這時候你已經得到了西夏的行數據中年齡列的最大值;
在外部WHERE查詢時,時針對整體行進行查詢,
所以他需要對條件【國籍=西夏】進行限定,使得過濾出【國籍=西夏】的數據。
WHERE和子語句組合使用使得你查詢的數據保持正確性。
如果在子查詢中使用了【國籍=西夏】的條件,
而WHERE併為進行條件過濾,那麼你其實是在做這麼一件事,
通過子語句得到一個最大值的年齡,比如16,
然後查詢所有【國籍=所有】學生,年齡=16的學生,共有多少人。
SQL
SELECT
max(age), COUNT(DISTINCT number)
FROM
students
WHERE
age = (SELECT max(age) FROM students WHERE nationality = '西夏');
但其實西夏的最大年齡16歲,學生只有1個
正確結果
本篇章講解了查詢中消除重複行的相關語法,
到此你應該能夠進行數據去重複業務上相關的數據操作。
Bye Bye.