Mysql表的查询(进阶)

个人简介

⭐️个人主页:摸鱼の文酱博客主页‍♂️
博客领域:java编程基础,mysql
写作风格:干货,干货,还是tmd的干货
精选专栏:【Java】【mysql】 【算法刷题笔记】
博主的码云gitee,平常博主写的程序代码都在里面。
支持博主:点赞、收藏⭐、留言
作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!

查询

  • 聚合查询
    • 数据准备
    • 聚合函数
    • GROUP BY
    • HAVING
  • 联合查询
    • 笛卡尔积
    • 内连接
    • 外连接
    • 自连接
    • 子查询
      • 单行子查询
      • 多行子查询
        • [not] in关键字:
        • [NOT] EXISTS关键字
    • 合并查询
      • union
      • union all

聚合查询

数据准备

先创建一个数据库,然后创建一个学生表,插入以下数据,后面操作时会用到

-- 创建学生表
create table student (id int primary key auto_increment, sn varchar(20),  name varchar(20), qq_mail varchar(20) ,
        classes_id int);
 -- 插入数据
insert into student(sn, name, qq_mail, classes_id) values
('09982','黑旋风李逵','[email protected]',1),
('00835','菩提老祖',null,1),
('00391','白素贞',null,1),
('00031','许仙','[email protected]',1),
('00054','不想毕业',null,1),
('51234','好好说话','[email protected]',2),
('83223','tellme',null,2),
('09527','老外学中文','[email protected]',2);    

Mysql表的查询(进阶)_第1张图片
创建成绩表:

-- 创建考试成绩表
DROP TABLE IF EXISTS exam_result;
CREATE TABLE exam_result (
id INT,
name VARCHAR(20),
chinese DECIMAL(3,1),
math DECIMAL(3,1),
english DECIMAL(3,1)
);
-- 插入测试数据
INSERT INTO exam_result (id,name, chinese, math, english) VALUES
(1,'唐三藏', 67, 98, 56),
(2,'孙悟空', 87.5, 78, 77),
(3,'猪悟能', 88, 98.5, 90),
(4,'曹孟德', 82, 84, 67),
(5,'刘玄德', 55.5, 85, 45),
(6,'孙权', 70, 73, 78.5),
(7,'宋公明', 75, 65, 30);

Mysql表的查询(进阶)_第2张图片

create table emp(
id int primary key auto_increment,
name varchar(20) not null,
role varchar(20) not null,
salary numeric(11,2)
);
insert into emp(name, role, salary) values
('马云','服务员', 1000.20),
('马化腾','游戏陪玩', 2000.99),
('孙悟空','游戏角色', 999.11),
('猪无能','游戏角色', 333.5),
('沙和尚','游戏角色', 700.33),
('隔壁老王','董事长', 12000.66);

Mysql表的查询(进阶)_第3张图片

聚合函数

  常见的统计总数、计算平局值等操作,可以使用聚合函数来实现,常见的聚合函数有:

函数 说明
COUNT([DISTINCT] expr) 返回查询到的数据的 数量
SUM([DISTINCT] expr) 返回查询到的数据的 总和,不是数字没有意义
AVG([DISTINCT] expr) 返回查询到的数据的 平均值,不是数字没有意义
MAX([DISTINCT] expr) 返回查询到的数据的 最大值,不是数字没有意义
MIN([DISTINCT] expr) 返回查询到的数据的 最小值,不是数字没有意义

让我们来看一下这些函数的使用效果:

COUNT
案例:

-- 统计班级共有多少同学
SELECT COUNT(*) FROM student;
-- 或者
SELECT COUNT(0) FROM student;
-- 统计班级收集的 qq_mail 有多少个,qq_mail 为 NULL 的数据不会计入结果
SELECT COUNT(qq_mail) FROM student;

班级总人数为8人
Mysql表的查询(进阶)_第4张图片
有qq邮箱的为4人
Mysql表的查询(进阶)_第5张图片

SUM
案例:

-- 统计数学成绩总分
SELECT SUM(math) FROM exam_result;
-- 不及格 < 60 的总分,没有结果,返回 NULL
SELECT SUM(math) FROM exam_result WHERE math < 60;

数学成绩总分:
Mysql表的查询(进阶)_第6张图片
数学低于60分
Mysql表的查询(进阶)_第7张图片
AVG
案例:

-- 统计平均总分
SELECT AVG(chinese + math + english) 平均总分 FROM exam_result;
-- 统计数学平均分
SELECT AVG(math) 数学平均分 FROM exam_result;

Mysql表的查询(进阶)_第8张图片
Mysql表的查询(进阶)_第9张图片

MAX
案例:

-- 返回英语最高分
SELECT MAX(english) FROM exam_result;

Mysql表的查询(进阶)_第10张图片

MIN
案例:

-- 返回 > 70 分以上的数学最低分
SELECT MIN(math) FROM exam_result WHERE math > 70;

Mysql表的查询(进阶)_第11张图片

GROUP BY

  SELECT 中使用 GROUP BY 子句可以对指定列进行分组查询。需要满足:使用 GROUP BY 进行分组查询时,SELECT 指定的字段必须是“分组依据字段”,其他字段若想出现在SELECT 中则必须包含在聚合函数中

语法

select column1, sum(column2), … from table group by column1,column3

案例

-- 查询每个角色的最高工资、最低工资和平均工资
select role,max(salary),min(salary),avg(salary) from emp group by role;

Mysql表的查询(进阶)_第12张图片

分组还可以指定条件筛选,如果是分组之前指定条件,使用where,如果是分组之后指定条件,使用having.

HAVING

  GROUP BY 子句进行分组以后,需要对分组结果再进行条件过滤时,不能使用 WHERE 语句,而需要用HAVING

案例:

-- 显示平均工资低于1500的角色和它的平均工资
select role,max(salary),min(salary),avg(salary) from emp group by role
having avg(salary)<1500;

Mysql表的查询(进阶)_第13张图片

联合查询

笛卡尔积

  实际开发中往往数据来自不同的表,所以需要多表联合查询。多表查询是对多张表的数据取笛卡尔积
  笛卡尔积的执行效率虽然不高,但其本身是一个功能挺好用的操作,有事可借助它完成更复杂的操作.
  但是,笛卡尔积也是一个危险的操作!!!,如果表内数据过多,贸然进行笛卡尔积,很可能会使数据库爆满.
  所以,开发过程中一般不用笛卡尔积来处理数据.
Mysql表的查询(进阶)_第14张图片
  笛卡尔积是两张表中的数据尽可能的排列组合得到的,在这些排列组合中的数据都是有用的吗?
  答案当然是不一定,这些数据有的是我们需要的,有的则没有意义.

案例:
1.查找同学姓名和对应班级的名字
Mysql表的查询(进阶)_第15张图片
将两张表做笛卡尔积后得到:
Mysql表的查询(进阶)_第16张图片
从结果中我们可以看到:两张表中都有classid这一列.
classId中的值对应相等的记录,这其实就是应该要保留的记录~~,
像这样的classId相等的条件,就称为==“连接条件”==

我们注意到绿框内的数据相等时,才是我们需要的正确数据,给上面的命令多加一个判断条件:

 select * from students,class  where students.classId = class.classId;

Mysql表的查询(进阶)_第17张图片
去掉其他多余的数据数据,只保留我们要的姓名和对应班级:

select students.name,class.name from students , class where students.classId = class.classId;

Mysql表的查询(进阶)_第18张图片

初始化测试数据

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','黑旋风李逵','[email protected]',1),
('00835','菩提老祖',null,1),
('00391','白素贞',null,1),
('00031','许仙','[email protected]',1),
('00054','不想毕业',null,1),
('51234','好好说话','[email protected]',2),
('83223','tellme',null,2),
('09527','老外学中文','[email protected]',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);

内连接

语法:

select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件;
select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其他条件;
案例

-- 查询“许仙”同学的 成绩
select sco.score from student stu inner join score sco on stu.id=sco.student_idand stu.name='许仙';
-- 或者
select sco.score from student stu, score sco where stu.id=sco.student_id and stu.name='许仙';

Mysql表的查询(进阶)_第19张图片
2.

-- 查询所有同学的总成绩,及同学的个人信息:
SELECT
	stu.sn,
	stu.NAME,
	stu.qq_mail,
	sum( sco.score )
FROM
	student stu
	JOIN score sco ON stu.id = sco.student_id
GROUP BY
	sco.student_id;

Mysql表的查询(进阶)_第20张图片
3.查询所有同学的成绩,及同学的个人信息:

select * from student stu join score sco on stu.id=sco.student_id;

查询出来的都是有成绩的同学,“老外学中文”同学 没有显示
Mysql表的查询(进阶)_第21张图片
4.

-- 学生表、成绩表、课程表3张表关联查询
SELECT
	stu.id,
	stu.sn,
	stu.NAME,
	stu.qq_mail,
	sco.score,
	sco.course_id,
	cou.NAME
FROM
	student stu
	JOIN score sco ON stu.id = sco.student_id
	JOIN course cou ON sco.course_id = cou.id
ORDER BY
	stu.id;

Mysql表的查询(进阶)_第22张图片

外连接

  外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完全显示我们就说是右外连接。

语法:

左外连接,表1完全显示
select 字段名 from 表名1 left join 表名2 on 连接条件;
右外连接,表2完全显示
select 字段 from 表名1 right join 表名2 on 连接条件

案例:查询所有同学的成绩,及同学的个人信息,如果该同学没有成绩,也需要显示
只要把成绩表对应的那一侧完全显示即可

-- “老外学中文”同学 没有考试成绩,也显示出来了
select * from student stu left join score sco on stu.id=sco.student_id;
-- 对应的右外连接为
select * from score sco right join student stu on stu.id=sco.student_id;
-- 学生表、成绩表、课程表3张表关联查询
SELECT
stu.id,
stu.sn,
stu.NAME,
stu.qq_mail,
sco.score,
sco.course_id,
cou.NAME
FROM
student stu
LEFT JOIN score sco ON stu.id = sco.student_id
LEFT JOIN course cou ON sco.course_id = cou.id
ORDER BY
stu.id;

Mysql表的查询(进阶)_第23张图片

自连接

自连接是指在同一张表连接自身进行查询。
案例:
显示所有“计算机原理”成绩比“Java”成绩高的成绩信息

- 先查询“计算机原理”和“Java”课程的id
select id,name from course where name='Java' or name='计算机原理';

Mysql表的查询(进阶)_第24张图片

-- 再查询成绩表中,“计算机原理”成绩比“Java”成绩 好的信息
SELECT
	s1.*
FROM
	score s1,
	score s2
WHERE
	s1.student_id = s2.student_id
	AND s1.score < s2.score
	AND s1.course_id = 1
	AND s2.course_id = 3;

Mysql表的查询(进阶)_第25张图片

	
-- 也可以使用join on 语句来进行自连接查询
SELECT
	s1.*
FROM
	score s1
	JOIN score s2 ON s1.student_id = s2.student_id
	AND s1.score < s2.score
	AND s1.course_id = 1
	AND s2.course_id = 3;

子查询

  子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询

单行子查询

返回一行记录的子查询

案例:
查询与“不想毕业” 同学的同班同学

select * from student where classes_id=(select classes_id from student where name='不想毕业');

Mysql表的查询(进阶)_第26张图片

多行子查询

[not] in关键字:
-- 使用IN
select * from score where course_id in (select id from course where
name='语文' or name='英文');
-- 使用 NOT IN
select * from score where course_id not in (select id from course where
name!='语文' and name!='英文');

[NOT] EXISTS关键字
-- 使用 EXISTS
select * from score sco where exists (select sco.id from course cou
where (name='语文' or name='英文') and cou.id = sco.course_id);
-- 使用 NOT EXISTS
select * from score sco where not exists (select sco.id from course cou
where (name!='语文' and name!='英文') and cou.id = sco.course_id);

  在from子句中使用子查询:子查询语句出现在from子句中。这里要用到数据查询的技巧,把一个子查询当做一个临时表使用

案例:
查询所有比“中文系2019级3班”平均分高的成绩信息

-- 获取“中文系2019级3班”的平均分,将其看作临时表
SELECT
avg( sco.score ) score
FROM
score sco
JOIN student stu ON sco.student_id = stu.id
JOIN classes cls ON stu.classes_id = cls.id
WHERE
cls.NAME = '中文系2019级3班';

Mysql表的查询(进阶)_第27张图片

合并查询

  在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all。
  使用UNION和UNION ALL时,前后查询的结果集中,字段需要一致。

union

  该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。

案例:
查询id小于3,或者名字为“英文”的课程:

select * from course where id<3
union
select * from course where name='英文';
-- 或者使用or来实现
select * from course where id<3 or name='英文';

Mysql表的查询(进阶)_第28张图片

union all

  该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。

案例:查询id小于3,或者名字为“Java”的课程

-- 可以看到结果集中出现重复数据Java
select * from course where id<3
union all
select * from course where name='英文';

Mysql表的查询(进阶)_第29张图片

你可能感兴趣的:(mysql,后端)