目录
1.聚合查询
1.1聚合函数
1.2GROUP BY子句
1.3HAVING
2.联合查询
联合查询步骤
2.1内连接
2.2外连接
2.3自连接
2.4子查询
单行子查询
多行子查询
2.5合并查询
UNION
UNION ALL
3.SQL关键字的使用顺序
3.1语法顺序
3.2执行顺序
1.聚合查询
聚合查询是SQL语句。它通过包含一个聚合函数(如 Sum 或 Avg )来汇总来自多个行的信息。
补充:聚合函数会忽略NULL值。
1.1聚合函数
函数 | 说明 |
COUNT([DISTINCT] expr) | 返回查询到的数据的数量 |
SUM([DISTINCT] expr) | 返回查询到的数据的总和,不是数字没有意义 |
AVG([DISTINCT] expr) | 返回查询到的数据的平均值,不是数字没有意义 |
MAX([DISTINCT] expr) |
返回查询到的数据的 最大值,不是数字没有意义
|
MIN([DISTINCT] expr) | 返回查询到的数据的 最小值,不是数字没有意义 |
示例:
这里准备了一个学生表和一个成绩表。
select * from student;
select * from exam_result;
1.COUNT函数
查询学生表中数据的数量
-- 写0和写*效果一样
select count(*)from student;
select count(0)from student;
结果为5条,NULL不会统计在内
统计id有多少个,结果为5
select count(id)from student;
2.SUM函数
统计数学成绩总分
select sum(math)from exam_result;
3.AVG函数
统计平均总分
select avg(chinese+math+english)from exam_result;
4.MAX函数
返回英语最高分
SELECT MAX(english) FROM exam_result;
5.MIN函数
返回70分以上的数学最低分
SELECT MIN(math) FROM exam_result WHERE math > 70;
1.2GROUP BY子句
SELECT中使用GROUPBY子句可以对指定列进行分组查询。需要满足:使用GROUPBY进行分组查询时,SELECT指定的字段必须是“分组依据字段”,其他字段若想出现在SELECT 中则必须包含在聚合函数中。
语法:
select column1, sum(column2), .. from table group by column1,column3;
示例:
准备测试表
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),
('王聪','游戏陪玩',9999.00),
('雅子','服务员',3544.90)
;
查询每个角色的最高工资,最低工资和平均工资:
1.首先要按照角色(role)进行分组
2.再通过聚合函数查询最高,最低和平均工资。
select role,max(salary),min(salary),avg(salary) from emp group by role;
1.3HAVING
GROUP BY子句进行分组以后,需要对分组结果进行条件过滤时,不能使用WHERE语句,需要使用HAVING。
例如:
显示平均工资低于1500的角色和它的平均工资。
1.先按照角色进行分组
2.分组之后查找工资低于1500的角色
3.通过聚合函数算出这些角色的平均工资
select role,avg(salary) as 平均工资 from emp group by role having avg(salary)<1500 ;
2.联合查询
联合查询是可合并多个相似的选择查询的结果集。等同于将一个表追加到另一个表,从而实现将两个表的查询组合到一起。使用条件查询所需要的数据。
笛卡尔乘积是指在数学中,两个集合X和Y的笛卡尓积(Cartesian product),又称直积,表示为X*Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员 。
假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。
用一些例子来看看联合查询到底是什么?
初始化测试数据:
classes表
create table classes(name varchar(255),learning varchar(255));
insert into classes(name, learning) values
('计算机系2019级1班', '学习了计算机原理、C和Java语言、数据结构和算法'),
('中文系2019级3班','学习了中国传统文学'),
('自动化2019级5班','学习了机械自动化');
student表
drop table student;
create table student(id int,name varchar(255),email varchar(255),classes_id int);
insert into student(id, name, email, 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);
course表
drop table course;
create table course(id int,name varchar(255));
insert into course(id,name) values
(1,'Java'),(2,'中国传统文化'),(3,'计算机原理'),(4,'语文'),(5,'高阶数学'),(6,'英文');
score表
create table score(score int,student_id int,course_id int);
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);
各表如下图所示:
联合查询步骤
1.先确定查询的数据在哪些表中
2.做一个笛卡尔积(全排列)
3.根据关联字段把无效数据过滤掉
4.根据业务需求使用where等关键字对有效数据行进行过滤
5.精简查询字段
2.1内连接
内连接(INNER JOIN)主要通过设置连接条件的方式,来移除查询结果中某些数据行的交叉连接。简单来说,就是利用条件表达式来消除交叉连接的某些数据行。
内连接使用 INNER JOIN 关键字连接两张表,并使用 ON 子句来设置连接条件。
语法:
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件;
select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其它条件;
例如:
1.查询‘许仙’同学的成绩:
通过连接student表和score表,查询许仙的成绩。
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.查询所有同学的总成绩以及个人信息:
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;
-- 学生表、成绩表、课程表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;
2.2外连接
外连接分为三种:左外连接,右外连接,全外连接。会返回每个满足第一个(顶端)输入与第二个(底端)输入的联接的行。它还返回任何在第二个输入中没有匹配行的第一个输入中的行。
左外连接:如果在连接查询中,连接管子左端的表中所有的元组都列出来,并且能在右端的表中找到匹配的元组,那么连接成功。如果在右端的表中,没能找到匹配的元组,那么对应的元组是空值(NULL)。
右外连接:与左外连接类似,只是右端表中的所有元组都列出,限制左端表的数据必须满足连接条件,而不管右端表中的数据是否满足连接条件,均输出表中的内容。
通俗易懂的说,就是如果联合查询,左侧的表完全显示我们就说是左外连接,右侧的表完全显示我们就说是右外连接。
语法:
-- 左外连接,表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;
2.3自连接
自连接是指在同一张表中连接自身进行查询。把列转换为行,从而实现数据之间的运算。
例如:
显示所有‘计算机原理’比‘Java’成绩高的成绩信息。
步骤:
1.找到涉及的表:course表和score表,从course表中找出对应的课程编号
select * from course;
2.从score表中找出对应的课程成绩,保证s1.course_id=3 and s2.course_id=1 and s1.student_id=s2.student_id。
select * from score s1,score s2;
select * from score s1,score s2 where s1.course_id=3 and s2.course_id=1 and s1.student_id=s2.student_id;
3. 查询‘计算机原理’比‘Java’成绩高的成绩信息,即s1.score>s2.score。
select * from score s1,score s2 where s1.course_id=3 and s2.course_id=1 and s1.student_id=s2.student_id and s1.score>s2.score;
全部代码如下:
-- 先查询“计算机原理”和“Java”课程的id
select id, name from course where name="计算机原理"or name="java";
-- 再查询成绩表中,“计算机原理”比“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;
-- 也可以使用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;
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 ="计算机原理";
2.4子查询
子查询,就是在一个查询中嵌套了其它查询,一个查询的条件依赖于另一个查询的结果。
单行子查询
返回一行记录的子查询。
例如:
查询“不想毕业”同学的同班同学。
按照之前的方法可以分两步查询:
1.找到涉及的表:student表,找到不想毕业在哪个班
select classes_id from student where name="不想毕业";
2.查询这个班中名字不为“不想毕业”的同学
select * from student where classes_id="1"and name!="不想毕业";
使用子查询一步就到位:
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="英文");
2.关键字[NOR]EXIST,EXISTS用于检查是否至少会返回一行数据,该子查询实际上并不返回任
何数据,而是返回True或False。
例如:
-- 使用 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);
2.5合并查询
在实际应用中,为了合并多个select的执行结果,可以使用集合操作符UNION,UNION ALL。使用时,前后查询的结果集中,字段需要一致。
UNION
该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果中的重复行。
例如:
查询id大于3,或者名字为“英文”的课程。
前者查询结果为:
select * from course where id>3;
后者查询结果为:
select * from course where name="英文";
使用union查询结果为:
UNION ALL
该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果中的重复行。
例如:
查询id大于3,或者名字为“英文”的课程。
select * from course where id>3 union all select * from course where name="英语";
3.SQL关键字的使用顺序
3.1语法顺序
- select[distinct]
- from
- join(如left join)
- on
- where
- group by
- having
- union
- order by
- limit
3.2执行顺序
- from
- on
- join
- where
- group by
- having
- select
- distinct
- union
- order by