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(二),有点小练习在等着你。。。
相关文章
相关标签/搜索