MySQL查询全解

接下来我们就要进入重中之重-----MySQL查询的学习中了.激动激动!!!!!!


1 聚合查询

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

COUNT

案例:
-- 统计班级共有多少同学
SELECT COUNT (*) FROM student;
SELECT COUNT ( 0 ) FROM student;

如果使用count等聚合函数的时候

count和()之间加上空格,此时就会使函数执行失败.

1)先执行 select* from exam result

2)根据上述的结果,执行 count

SUM

-- 统计班级收集的 qq_mail 有多少个, qq_mail NULL 的数据不会计入结果
SELECT COUNT (qq_mail) FROM student;
-- 统计数学成绩总分
SELECT SUM (math) FROM exam_result;
-- 不及格 < 60 的总分,没有结果,返回 NULL
SELECT SUM (math) FROM exam_result WHERE math < 60 ;

要确保求和的列是数字,如果是字符串,就会出现问题

原则上不应该针对字符串进行上述的求和操作.

即使你的字符串带有数字,也不一定可以进行算术运算.

手机号码/身份证号码 .....

null,null 和其他数值进行各种运算,结果都是 null

但是在sum比较特殊,遇到null会直接跳过,不参与运算 ~~

要求列是数字

AVG

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

MAX

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

MIN

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

1.2 GROUP BY子句

SELECT 中使用 GROUP BY 子句可以对指定列进行分组查询。需要满足:使用 GROUP BY 进行分组查 询时,SELECT 指定的字段必须是 分组依据字段 ,其他字段若想出现在 SELECT 中则必须包含在聚合函 数中。
select........from ...group by ...
案例:
准备测试表及数据:职员表,有 id (主键)、 name (姓名)、 role (角色)、 salary (薪水)
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 );
查询每个角色的最高工资、最低工资和平均工资
select role,max(salary),min(salary),avg(salary) from emp group by role;

1.3 HAVING

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

1)分组之后的条件

每个岗位查询平均薪资,排除平均薪资超过5w的记录~

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

2)一个查询,可以同时包含,分组前的条件,和分组后的条件.

统计每个岗位平均薪资,排除张三,也排除平均值超过5w的结果

当前这里的情况,就是能够把两种条件结合到一起.

后续做类似的场景的时候,需要区分好,条件是分组之前的,还是分组之后的.

2 联合查询

实际开发中往往数据来自不同的表,所以需要多表联合查询。多表查询是对多张表的数据取笛卡尔积:


先明确要查询的数据,都在哪几个表中.
a)笛卡尔积.
b)指定连接条件,把一些无意义的数据干掉.
c)进一步添加筛选条件.
d)把查询的列进行精简.

进行计算笛卡尔积的表,要能够包含列进行关联.

注意 :关联查询可以对关联表使用别名。
初始化测试数据:
指定连接条件
查询操作后列表
把列经行精简

内连接

语法:
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件;
select 字段 from 表1 别名1 ,表2 别名2 where 连接条件 and 其他条件;
案例:
1 )查询 许仙 同学的 成绩
select sco .score from student stu inner join score sco on stu .id =sco .student_id
and stu .name = ' 许仙 ' ;
-- 或者
select sco .score from student stu, score sco where stu .id =sco .student_id and
stu .name = ' 许仙 ' ;
2 )查询所有同学的总成绩,及同学的个人信息:
-- 成绩表对学生表是多对 1 关系,查询总成绩是根据成绩表的同学 id 来进行分组的
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 ;
3 )查询所有同学的成绩,及同学的个人信息:
-- 查询出来的都是有成绩的同学, 老外学中文 同学 没有显示
select * from student stu join score sco on stu .id =sco .student_id ;

外连接

外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完 全显示我们就说是右外连接。
语法
-- 左外连接,表 1 完全显示
select 字段名   from 表名 1 left join 表名 2 on 连接条件 ;
-- 右外连接,表 2 完全显示
select 字段 from 表名 1 right join 表名 2 on 连接条件 ;

外连接,也是join on这样的写法(不支持from多个表 .... )

给join前面加上left/right就是表示外连接.

-- “ 老外学中文 同学 没有考试成绩,也显示出来了
select * from student stu left join score sco on stu .id =sco .student_id ;
左外连接就是以左表为基准
能够确保左表中的每个记录都出现在最终结果里.
如果左表中的记录,在右表中没有对应的记录,此时就会把右表中的相关字段,填成 NULL
-- 对应的右外连接为:
select * from score sco right join student stu on stu .id =sco .student_id ;
右外连接,是以右表为基准
然后确保右表中的每个记录都出现在最终结果里
如果右表中的某个记录在左表里没有对应的相关字段,填成 NULL
-- 学生表、成绩表、课程表 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 ;
总结:
全外连接

5 自连接

自连接是指在同一张表连接自身进行查询
案例:
显示所有 计算机原理 成绩比 “Java” 成绩高的成绩信息
-- 先查询 计算机原理 “Java” 课程的 id
select id,name from course where name= 'Java' or name= ' 计算机原理 ' ;
-- 再查询成绩表中, 计算机原理 成绩比 “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 ;

针对这一行来说,左侧的score列就是计算机原理的分数,右侧的score 列就是java的分数

这里原来的行之间的关系变成了列之间的关系了.

按照 学生id 做为连接条件的时候,此时 分数 和 课程id 就相当于是在进行排列组合

这些排列组合里就包括了两个神奇的数据 !!!

-- 也可以使用 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
stu.*,
s1 .score Java,
s2 .score 计算机原理
FROM
score s1
JOIN score s2 ON s1 .student_id = s2 .student_id
JOIN student stu ON s1 .student_id = stu .id
JOIN course c1 ON s1 .course_id = c1 .id
JOIN course c2 ON s2 .course_id = c2 .id
AND s1 .score < s2 .score
AND c1 .NAME = 'Java'
AND c2 .NAME = ' 计算机原理 ' ;
案例:查询所有同学的成绩,及同学的个人信息,如果该同学没有成绩,也需要显示

子查询(不推荐)

子查询是指嵌入在其他 sql 语句中的 select 语句,也叫嵌套查询
单行子查询:返回一行记录的子查询
查询与 不想毕业 同学的同班同学:
select * from student where classes_id=(select classes_id from student where name='不想毕业');
多行子查询:返回多行记录的子查询
案例:查询 语文 英文 课程的成绩信息
1. [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!= ' 英文 ' );
-- 插入重复的分数: score, student_id, course_id 列重复
insert into score(score, student_id, course_id) values
-- 黑旋风李逵
( 70.5 , 1 , 1 ),( 98.5 , 1 , 3 ),
-- 菩提老祖
( 60 , 2 , 1 );
-- 查询重复的分数
SELECT
*
FROM
score
WHERE
( score, student_id, course_id ) IN ( SELECT score, student_id,
course_id FROM score GROUP BY score, student_id, course_id HAVING
count ( 0 ) > 1 );
2. [NOT] EXISTS 关键字:

子查询本身就不推荐使用了.

exists 非常消耗时间,背后会触发大量的硬盘IO操作.并且代码理解起来也比较复杂 ....

-- 使用 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 ' ;
查询成绩表中,比以上临时表平均分高的成绩:
SELECT
*
FROM
score sco,
(
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 '
) tmp
WHERE
sco .score > tmp .score ;

合并查询

在实际应用中,为了合并多个 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= ' 英文 ' ;

union all

该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。
案例:查询 id 小于 3 ,或者名字为 “Java” 的课程
-- 可以看到结果集中出现重复数据 Java
select * from course where id< 3
union all
select * from course where name='英文';

 

如果您觉得有失偏颇请您在评论区指正,如果您觉得不错的话留个好评再走吧!!

您的鼓励就是对我最大的支持!  ! !

  • 17
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值