Mysql關鍵字之Group By(一)

原文地址,優先更新https://hhe0.github.iohtml

group by 是一個咱們在平常工做學習過程當中常常遇到的一個Mysql關鍵字。現總結其用法以下,內容會不斷補充,出現錯誤歡迎批評指正。mysql

咱們先準備一張表和一些記錄

咱們首先建立學生的成績表courses:git

CREATE TABLE `courses` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增id',
`student` VARCHAR(255) DEFAULT NULL COMMENT '學生',
`class` VARCHAR(255) DEFAULT NULL COMMENT '課程',
`score` INT(255) DEFAULT NULL COMMENT '分數',
PRIMARY KEY (`id`),
UNIQUE KEY `course` (`student`, `class`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

該表記錄了學生某節課的考試分數。
courses表中插入記錄:github

INSERT INTO `courses`(`student`, `class`, `score`) VALUES('A', 'Math', 90);
INSERT INTO `courses`(`student`, `class`, `score`) VALUES('A', 'Chinese', 80);
INSERT INTO `courses`(`student`, `class`, `score`) VALUES('A', 'English', 70);
INSERT INTO `courses`(`student`, `class`, `score`) VALUES('A', 'History', 80);

INSERT INTO `courses`(`student`, `class`, `score`) VALUES('B', 'Math', 73);
INSERT INTO `courses`(`student`, `class`, `score`) VALUES('B', 'Chinese', 60);
INSERT INTO `courses`(`student`, `class`, `score`) VALUES('B', 'English', 70);
INSERT INTO `courses`(`student`, `class`, `score`) VALUES('B', 'History', 90);

INSERT INTO `courses`(`student`, `class`, `score`) VALUES('C', 'Math', 70);
INSERT INTO `courses`(`student`, `class`, `score`) VALUES('C', 'Chinese', 50);
INSERT INTO `courses`(`student`, `class`, `score`) VALUES('C', 'English', 20);
INSERT INTO `courses`(`student`, `class`, `score`) VALUES('C', 'History', 10);

INSERT INTO `courses`(`student`, `class`, `score`) VALUES('D', 'Math', 53);
INSERT INTO `courses`(`student`, `class`, `score`) VALUES('D', 'Chinese', 32);
INSERT INTO `courses`(`student`, `class`, `score`) VALUES('D', 'English', 99);
INSERT INTO `courses`(`student`, `class`, `score`) VALUES('D', 'History', 100);

Group By有什麼用

咱們使用幾個簡單的例子看一下group by的做用:sql

SELECT * FROM `courses` GROUP BY `class`;

執行的結果是:
微信

企業微信截圖_20180820143057.png-7.3kB

相似地,咱們按照 score對記錄進行分組:

SELECT * FROM `courses` GROUP BY `score`;

執行的結果是:
學習

ScreenClip.png-13.8kB

咱們甚至能夠對多個字段進行 group by

SELECT * FROM `courses` GROUP BY `class`,`student`;

執行的結果是:
3d

ScreenClip.png-14.3kB

最後,咱們交換字段順序對記錄進行分組:

SELECT * FROM `courses` GROUP BY `student`,`class`;

執行的結果是:
code

ScreenClip.png-17.2kB

這樣的結果可能會令人困惑,咱們以第一個sql爲例,解釋下sql執行的過程:
未命名文件.png-62.2kB

sql首先會按照 class進行分組獲得四張中間表,而後輸出的時候將每個分組的第一個記錄組合在一塊兒造成了最終的結果。咱們還能夠發現,最終的記錄是按照 class進行排序的。這樣的順序並不可靠,具體造成的緣由恐怕須要在 Mysql的底層原理中找到答案。

Group By還能怎麼用

與order by結合在一塊兒使用

咱們須要學生的成績表,且每一個學生每科的成績按照由大到小的順序排列htm

咱們能夠很天然的寫出下面的sql:

SELECT * FROM `courses` GROUP BY `student`,`class` ORDER BY `score` DESC;

然而,執行的結果貌似並非咱們想要的:

ScreenClip.png-16.6kB

經過觀察,咱們能夠發現,事實上,這個 sql是將全部的記錄按照 score由大到小的順序排列了,爲何會出現這樣的結果呢?
事實上,這個取決於整個 sql的執行順序,真正的執行順序是 from ... where ... group by ... order by ... selectorder by 做用在整個記錄,而不是每一個分組上。
那麼,怎麼樣可以獲得咱們指望的結果呢?這裏給出個人 sql實現:

SELECT * FROM `courses` GROUP BY `student`,`class` ORDER BY `student`,`score` DESC;

執行的結果是:

ScreenClip.png-19.8kB

與having結合在一塊兒使用

咱們須要獲得全部功課平均分達到60分的同窗和他們的均分:

SELECT `student`, AVG(`score`) AS`avg_score`
FROM `courses`
GROUP BY `student`
HAVING AVG(`score`) >= 60
ORDER BY `avg_score` DESC;

執行的結果爲:

ScreenClip (8).png-3.8kB

這裏須要注意一個問題: wherehaving的區別。 where做用於全部的記錄,而 having則做用於一個分組。
舉例說明:

假設咱們這裏須要獲得全部功課(除歷史課)平均分達到60分的同窗和他們的均分:

SELECT `student`, AVG(`score`) AS `avg_score`
FROM `courses`
WHERE `class` <> 'History'
GROUP BY `student`
HAVING AVG(`score`) >= 60
ORDER BY `avg_score` DESC;

執行的結果以下:

ScreenClip.png-3.1kB

Group By與Limit

咱們須要列出均分最高的三門課:

SELECT `class`, AVG(`score`) AS `avg_score`
FROM `courses`
GROUP By `class`
ORDER BY `avg_score` DESC
LIMIT 3;

執行的結果以下:

ScreenClip.png-3.8kB

咱們須要理解的是: group by分組的依據,以及 where過濾條件做用的粒度
若是你以爲你已經理解了 group by關鍵字的用法,歡迎移步至 Mysql關鍵字之Group By(二),有點小練習在等着你。。。
相關文章
相關標籤/搜索