聚合查询
1 聚合函数
主要对于行与行之间的操作 聚合函数的作用是对一组数据进行计算,通常返回一个单一的结果。它们常用于数据汇总、统计和分析。
常见的统计总数、计算平局值等操作,可以使用聚合函数来实现,常见的聚合函数有:
|--------------------------|------------------------|
| 函数 | 说明 |
| COUNT([DISTINCT] expr) | 返回查询到的数据的 数量 |
| SUM([DISTINCT] expr) | 返回查询到的数据的 总和,不是数字没有意义 |
| AVG([DISTINCT] expr) | 返回查询到的数据的 平均值,不是数字没有意义 |
| MAX([DISTINCT] expr) | 返回查询到的数据的 最大值,不是数字没有意义 |
| MIN([DISTINCT] expr) | 返回查询到的数据的 最小值,不是数字没有意义 |
案例:
COUNT
- 作用:返回某列的非 NULL 值的数量,或返回满足条件的行数。
- 语法
sql
COUNT(column_name) -- 统计指定列非 NULL 的值的数量
COUNT(*) -- 统计所有行的数量
当具体对某个列查询的时候 count会关注null值 并且不会包含它
如果对整个表进行count 则不会关注null
SUM()
- 作用:返回某列数值型数据的总和。
- 语法:
sql
SUM(column_name)
求语文分数的总和
求语文+数学+英语分数的总和
AVG()
- 作用:返回某列数值型数据的平均值。
- 语法:
sql
AVG(column_name)
统计总分平均总分
MAX()
- 作用:返回某列中的最大值。
- 语法:
sql
MAX(column_name)
MIN()
- 作用:返回某列中的最小值。
- 语法
sql
MIN(column_name)
求语文的最高分 和 英语的最低分
GROUP BY子句
SELECT 中使用 GROUP BY 子句可以对指定列进行分组查询。需要满足:使用 GROUP BY 进行分组查询时,SELECT 指定的字段必须是"分组依据字段",其他字段若想出现在SELECT 中则必须包含在聚合函数中。
- 查询每个岗位的人数
按照role进行分组 ,再根据分组的结果使用count聚合函数统计它的人数即可
- 统计每个岗位的平均工资
- 查询每个角色的人数和最高工资、最低工资和平均工资
HAVING
HAVING
是一个用于对查询结果进行过滤的 SQL 语句,它通常与 GROUP BY
一起使用,用于过滤分组后的结果。与 WHERE
不同,HAVING
是在对数据进行分组(GROUP BY
)之后进行过滤的,而 WHERE
是在分组之前对数据进行过滤的。
显示平均工资大于10000的角色和它的平均工资
联合查询
实际开发中往往数据来自不同的表,所以需要多表联合查询。多表查询是对多张表的数据取笛卡尔积
啥是笛卡尔积?
- 笛卡尔积(CROSS JOIN):将两个表中的每一行与另一表的每一行进行组合,生成结果集的行数是两个表行数的乘积,通常会产生非常大的结果集。
示例:
以上所有数据就是笛卡尔积 但是有很多错误信息 他们并不匹配 所有需要进一步细分
此时就可以发现数据一一对应上了 这就是多表查询;
初始化数据,以便下一步的学习
sql
insert into classes(name, `desc`) values
('计算机系2019级1班', '学习了计算机原理、C和Java语言、数据结构和算法'),
('中文系2019级3班','学习了中国传统文学'),
('自动化2019级5班','学习了机械自动化');
insert into student(sn, name, qq_mail, classes_id) values
('09982','黑旋风李逵','xuanfeng@qq.com',1),
('00835','菩提老祖',null,1),
('00391','白素贞',null,1),
('00031','许仙','xuxian@qq.com',1),
('00054','不想毕业',null,1),
('51234','好好说话','say@qq.com',2),
('83223','tellme',null,2),
('09527','老外学中文','foreigner@qq.com',2);
insert into course(name) values
('Java'),('中国传统文化'),('计算机原理'),('语文'),('高阶数学'),('英文');
insert into score(score, student_id, course_id) values
-- 黑旋风李逵
(70.5, 1, 1),(98.5, 1, 3),(33, 1, 5),(98, 1, 6),
-- 菩提老祖
(60, 2, 1),(59.5, 2, 5),
-- 白素贞
(33, 3, 1),(68, 3, 3),(99, 3, 5),
-- 许仙
(67, 4, 1),(23, 4, 3),(56, 4, 5),(72, 4, 6),
-- 不想毕业
(81, 5, 1),(37, 5, 5),
-- 好好说话
(56, 6, 2),(43, 6, 4),(79, 6, 6),
-- tellme
(80, 7, 2),(92, 7, 6);
1 内连接
语法:
sql
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件;
select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其他条件;
俩种写法都可以;
案例:
(1)查询"许仙"同学的 成绩
首先看到题目先确定查询的信息来自于哪张表?
很明显来自 student表和score表
接着对俩张表进行笛卡尔积
sqlselect * from student,score;
这些数据是全部排列组合的结果,并不是我们全部想要的;
缩小范围 加上条件 student.id = score.id
sqlselect * from student,score where student.id = score.student_id;
最后补下其他条件即可
sqlselect student.name,score.score from student,score where student.id = score.student_id and student.name = '许仙';
join on 写法
sqlselect student.name,score.score from student join score on student.id = score.student_id and student.name = '许仙';
注意: 如果在实际开发中 谨慎使用笛卡尔积 如果表中数据很大,容易把mysql弄崩溃
(2)查询所有同学的总成绩,及同学的个人信息:
成绩在score表 个人信息在学生表
总成绩需要使用到聚合函数 可以按照学生名字进行分组
sqlselect * from student,score where student.id = score.student_id group by student.name;
进行求和 并且留下指定列
sqlselect student.name,sum(score) as '总成绩' from student,score where student.id = score.student_id group by student.name;
join on 写法:
sqlselect student.name,sum(score) as '总成绩' from student join score on student.id = score.student_id group by student.name;
3)查询所有同学的成绩,及同学的个人信息:列出 同学的名称 课程的名字 以及课程的成绩
提取关键词:成绩在score表 同学在student表 个人信息在course表
sqlselect * from student,course,score;
数据相当大 对它进行细节划分
sqlselect * from student,course,score where student.id = score.student_id and score.course_id = course.id;
对列进行精简即可
sqlselect student.name as '学生名称' , course.name as '科目名称' , score.score from student,course,score where student.id = score.student_id and score.course_id = course.id;
join on 写法
sqlselect student.name as '学生名称' , course.name as '科目名称' , score.score from student join course on student.id = course.id join score on score.course_id = course.id;
2 外连接
外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完全显示我们就说是右外连接。
语法:
sql
-- 左外连接,表1完全显示
select 字段名 from 表名1 left join 表名2 on 连接条件;
-- 右外连接,表2完全显示
select 字段 from 表名1 right join 表名2 on 连接条件;
内连接:
左外连接:
右外连接:
俩张表存在一一对应的情况 ,所有内连接和外连接找到的结果都是一致的;
当修改其中某个值,让它们不保存一一对应的情况内连接:
左外连接:
右外连接:
当对应不存在的列 会用null填充
3 自连接
自连接是指在同一张表连接自身进行查询。
案例:
显示所有"计算机原理"成绩比"Java"成绩高的成绩信息
行与行比较大小 怎么办?
只能将它们转化成列与列比较大小,自连接将可以完成操作 自己与自己笛卡尔积
进行不断筛选
并且让s1 为计算机原理 课程id为3 s2为java 课程id 为1
最后进行大于 筛选
sqlselect * from score as s1 ,score as s2 where s1.student_id = s2.student_id and s1.course_id = 3 and s2.course_id = 1 and s1.score > s2.score;
4 子查询
子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询,
简单来说就是把多个sql语句写成一个sql;
单行子查询:返回一行记录的子查询
查询与"不想毕业" 同学的同班同学:
思路:在student表中找到"不想毕业" 同学的classes_id 再在student表中找到与它id相同的同学
1.
sqlselect name from student where classes_id = 1;
sqlselect name from student where classes_id = 1 and name != '不想毕业';
一行写完:
sqlselect name from student where classes_id = (select classes_id from student where name = '不想毕业') and name != '不想毕业';
多行子查询:返回多行记录的子查询案例:查询"语文"或"英文"课程的成绩信息
思路:在course表中找到"语文"或"英文"课程的id 再在score表找到 id为它们的分数
1.
sqlselect id from course where name = '语文' or name = '英文';
sqlselect score from score where course_id in(4,6);
一行写完:
sqlselect score from score where course_id in(select id from course where name = '语文' or name = '英文');
5 合并查询
在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all。使用UNION和UNION ALL时,前后查询的结果集中,字段需要一致。
将最终结果合并在一起,整体过程与执行多个sql操作类似;
查询id小于3,或者名字为"英文"的课程:
sqlselect * from course where id < 3 union select * from course where name = '英文';
也可以直接使用or;
但是union的作用可以在不同的表的使用 并于合并
而or只能在同一张表中使用