產品操作MySQL第5篇 – 資料查詢-排重查詢

MYSQL
本資料為產品崗位作為日常工作參考,語言口語化
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.