Mysql關鍵字之Group By(一)


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

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

我們先准備一張表和一些記錄

我們首先創建學生的成績表courses:

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表中插入記錄:

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的作用:

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

執行的結果是:

![企業微信截圖_20180820143057.png-7.3kB][1]
類似地,我們按照`score`對記錄進行分組: ```sql SELECT * FROM `courses` GROUP BY `score`; ``` 執行的結果是:
![ScreenClip.png-13.8kB][2]
我們甚至可以對多個字段進行`group by`: ```sql SELECT * FROM `courses` GROUP BY `class`,`student`; ``` 執行的結果是:
![ScreenClip.png-14.3kB][3]
最后,我們交換字段順序對記錄進行分組: ```sql SELECT * FROM `courses` GROUP BY `student`,`class`; ``` 執行的結果是:
![ScreenClip.png-17.2kB][4]
這樣的結果可能會使人困惑,我們以第一個sql為例,解釋下sql執行的過程:
![未命名文件.png-62.2kB][5]
該`sql`首先會按照`class`進行分組得到四張中間表,然后輸出的時候將每一個分組的第一個記錄組合在一起形成了最終的結果。我們還可以發現,最終的記錄是按照`class`進行排序的。這樣的順序並不可靠,具體形成的原因恐怕需要在`Mysql`的底層原理中找到答案。 ## Group By還能怎么用 ### 與order by結合在一起使用 > 我們需要學生的成績表,且每個學生每科的成績按照由大到小的順序排列

我們可以很自然的寫出下面的sql:

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

然而,執行的結果貌似並不是我們想要的:

![ScreenClip.png-16.6kB][6]
通過觀察,我們可以發現,事實上,這個`sql`是將所有的記錄按照`score`由大到小的順序排列了,為什么會出現這樣的結果呢? 事實上,這個取決於整個`sql`的執行順序,真正的執行順序是 `from` ... `where` ... `group by` ... `order by` ... `select`,`order by` 作用在整個記錄,而不是每個分組上。 那么,怎么樣能夠得到我們期望的結果呢?這里給出我的`sql`實現: ```sql SELECT * FROM `courses` GROUP BY `student`,`class` ORDER BY `student`,`score` DESC; ``` 執行的結果是:
![ScreenClip.png-19.8kB][7]

與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][8]
這里需要注意一個問題:`where` 與 `having`的區別。`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][9]
### 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][10]
我們需要理解的是:`group by`分組的依據,以及`where`過濾條件作用的粒度 如果你覺得你已經理解了`group by`關鍵字的用法,歡迎移步至 Mysql關鍵字之Group By(二),有點小練習在等着你。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM