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)把查询的列进行精简.
进行计算笛卡尔积的表,要能够包含列进行关联.
注意
:关联查询可以对关联表使用别名。
初始化测试数据:
指定连接条件
查询操作后列表
把列经行精简
3 内连接
语法:
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
;
4 外连接
外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完 全显示我们就说是右外连接。
语法
--
左外连接,表
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
=
'
计算机原理
'
;
案例:查询所有同学的成绩,及同学的个人信息,如果该同学没有成绩,也需要显示
6 子查询(不推荐)
子查询是指嵌入在其他
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
;
7 合并查询
在实际应用中,为了合并多个
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='英文';
如果您觉得有失偏颇请您在评论区指正,如果您觉得不错的话留个好评再走吧!!
您的鼓励就是对我最大的支持! ! !