mysql group by 用法
分组查询是对数据按照某个字段或多个字段进行分组,Mysql 中使用 group by 实现
[group by 字段] [having <条件表达式>]
字段指的是分组时依据的字段,having 用来对分组之后的数据进行筛选
数据准备
接下来的内容都基于如下测试数据
sql如下:
CREATE TABLE `score_test` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`student_id` int(11) NOT NULL DEFAULT '-1' COMMENT '学生id',
`name` varchar(125) NOT NULL DEFAULT '' COMMENT '姓名',
`sex` int(1) NOT NULL DEFAULT '-1' COMMENT '性别 1男 2女',
`subject` int(1) NOT NULL DEFAULT '-1' COMMENT '学科 1语文,2数学,3英语',
`score` int(3) NOT NULL DEFAULT '-1' COMMENT '分数',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最近更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='期中成绩表';
INSERT INTO `score_test` (`id`, `student_id`, `name`, `sex`, `subject`, `score`, `created_at`, `updated_at`)
VALUES
(1, 2012010123, '小明', 1, 1, 100, '2020-10-27 18:28:06', '2020-10-27 18:28:41'),
(2, 2012010123, '小明', 1, 2, 97, '2020-10-27 18:28:11', '2020-10-27 18:28:45'),
(3, 2012010123, '小明', 1, 3, 67, '2020-10-27 18:28:47', '2020-10-27 21:11:21'),
(4, 2012010124, '小红', 2, 1, 98, '2020-10-27 21:11:15', '2020-10-27 21:15:13'),
(5, 2012010124, '小红', 2, 2, 88, '2020-10-27 21:11:53', '2020-10-27 21:15:11'),
(6, 2012010124, '小红', 2, 3, 100, '2020-10-27 21:11:54', '2020-10-27 21:15:09'),
(7, 2012010125, '小王', 1, 1, 100, '2020-10-27 21:12:04', '2020-10-27 21:15:35'),
(8, 2012010125, '小王', 1, 2, 100, '2020-10-27 21:12:07', '2020-10-27 21:15:37'),
(9, 2012010125, '小王', 1, 3, 100, '2020-10-27 21:14:36', '2020-10-27 21:15:39'),
(10, 2012010126, '小紫', 2, 1, 44, '2020-10-27 21:15:44', '2020-10-27 21:16:23'),
(11, 2012010126, '小紫', 2, 2, 50, '2020-10-27 21:15:48', '2020-10-27 21:16:25'),
(12, 2012010126, '小紫', 2, 3, 62, '2020-10-27 21:15:50', '2020-10-27 21:16:28');
创建分组
通常 group by 会结合统计函数一起使用 ,例如 MAX() MIN() COUNT() SUM() AVG()。
我们来统计一下每个人所有学科的总分
根据姓名对score_test表进行分组
select name,sum(score) as total from score_test group by name
输出如下
可以看到分别计算出了所有学生的总分,group by 先对数据进行分组,再在各个分组数据中进行统计运算,最后返回结果
隐含字段
在标准的sql中,查询的字段必须出现在group by 子句中。比如说我们还想查student_id,那按照标准sql的语法,sql如下
select name,sum(score),student_id as total from score_test group by name,student_id
为甚么要求这样呢?
如果我们查询了没在group by子句中出现的字段,并且该字段在该组中不唯一,将会得到非预测性结果。
大家可以设想一下下面这条sql的输出,我们无法预测subject的返回,这种场景也不会存在。
select name,sum(score) as total,subject from score_test group by name
但是按照name分组,每组数据中的student_id是唯一的。也就意味着结果是可预测的。即使如此,标准sql也不予许省略group by 字句中的student_id
select name,sum(score) as total,student_id from score_test group by name
那Mysql中又是如何规范的呢?
MySQL 扩展了 GROUP BY的用途,因此你可以使用SELECT 列表中不出现在GROUP BY语句中的列或运算,在有些情况下,你可以使用MIN()和MAX() 获取一个特殊的列值,即使他不是唯一的
假如你从 GROUP BY 部分省略的列在该组中不是唯一的,那么不要使用这个功能! 你会得到非预测性结果。
GROUP_CONCAT
如果还想获取每个学生的科目,可以使用group_concat,将每个分组中各个字段的值显示出来
select name,sum(score) as total,group_concat(subject) as subjects from score_test group by name
使用HAVING 过滤分组
group by 可以和 having 配合使用,来过滤分组之后的数据
我们来查一下总分在200分以上的学生成绩
select name,sum(score) as total,group_concat(subject) as subjects from score_test group by name having total>200
HAVING 关键字和 WHERE 关键字都是用来过滤数据的,两者有什么区别呢? HAVING 在数据分组之后进行过滤来选择分组,而WHERE在分组之前用来筛选记录,被WHERE排除的记录不会包括在分组中。