聚合查询+联合查询+子查询
文章目录
- 一、聚合查询
- 1.聚合函数
- 2.GROUP BY子句
- 3.HAVING
- 二、联合查询
- join on
- 1.内连接
- 2.外连接
- 3.自连接
- 三、子查询
- EXISTS关键字
- 四、联合查询
- 总结
一、聚合查询
1.聚合函数
常见的统计总数,计算平均值的操作,可以用聚合函数来实现,常见的聚合函数有:
这些函数都比较简单,通过几条SQL语句就能理解
- count
-- 求表中一共有多少个学生select count(*) from student;-- 求共有多少学提供了 qq邮箱select count(qq_mail) from student;
注意: count()之间不能有空格,且null不会记录到最终结果中
count 函数相当于是先执行select * ,再根据 select * 放回的结果统计数量
- sum
-- 统计数学成绩总分
SELECT SUM(math) FROM exam_result;
-- 不及格 < 60 的总分,没有结果,返回 NULL
SELECT SUM(math) FROM exam_result WHERE math < 60;
- 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;
2.GROUP BY子句
SELECT 中使用 GROUP BY 子句可以对指定列进行分组查询。需要满足:使用 GROUP BY 进行分组查询时,SELECT 指定的字段必须是“分组依据字段”,其他字段若想出现在SELECT 中则必须包含在聚合函数中
-- 创建表
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('孙悟空','员工',3300.5),('猪八戒','员工',4000),('沙僧','员工',3700.50),('唐僧','主管',6000),('白龙马','主管',5800),('老王','老板',10000.88);
用 group by 对 role 职位分组,分别求每个职位的最高工资、最低工资何平均工资
select role,max(salary),avg(salary), avg(salary) from emp group by role;
3.HAVING
GROUP BY 子句进行分组以后,需要对分组结果再进行条件过滤时。
注意:where 的条件筛选是针对当前表中原始的数据(聚合前的数据)来进行筛选, 而现在咱们是期望针对聚合后的数据进行筛选
针对聚合后的数据进行筛选,要使用的是 having 子句,语法和 where 类似。
代码示例:
我们要查询一个平均薪资大于4000的岗位,以岗位分组。
select role, avg(salary) from emp
group by role having avg(salary) > 4000;
where 也能和 group by 搭配 只不过这样的搭配是根据需求来确定
如果需求中的条件,是针对聚合前的的数据进行筛选,就使用 where
如果需求中的条件,是针对聚合后的的数据进行筛选,就使用 having
代码示例:
我们要查询一个平均薪资大于4000的岗位且排除掉唐僧,使用 where条件过滤掉唐僧,唐僧就不会被分到任何组了
select role, avg (salary) from empwhere name != '唐僧' group by role having avg(salary) > 4000;
二、联合查询
实际开发中往往数据来自不同的表,所以需要多表联合查询。多表查询是对多张表的数据取笛卡尔积,也就是获取两个表的排列组合,把两张表中数据组合的所有可能都列举出来。但是有很多数据是没有意义的。
在 SQL中计算笛卡尔积(多表查询)主要有两种方式
1.直接 select from 表1,表2…
2.select from 表1 join 表2 on 条件… join 表3 on 条件
注意:在SQL中如果两个表的字段名冲突可以通过点来指定某张表的字段,类似于Java的成员访问操作符。
表名.字段名,
同样可以
数据库名.表名.字段名
代码示例:
创建一个班级表、学生表,课程表,和分数表。
drop table if exists classes;
drop table if exists student;
drop table if exists course;
drop table if exists score;create table classes (id int primary key auto_increment, name varchar(20), `desc` varchar(100));create table student (id int primary key auto_increment, sn varchar(20), name varchar(20), qq_mail varchar(20) ,classes_id int);create table course(id int primary key auto_increment, name varchar(20));create table score(score decimal(3, 1), student_id int, course_id int);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','曹操',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),
-- 曹操
(80, 7, 2),(92, 7, 6);
共创建了4张表
分数表就是课程表和学生表的中间表
再进行笛卡尔积(多表查询)
select * from classes,course,score,student;
得到了2000多行数据,但笛卡尔积是无脑排列组合这里大部分数据是没有意义的。
我们就要对数据进行筛选,筛选出 分数表中student_id和学生表中id相等的数据
select * from student, score where student.id = score.student_id;
假如我们要查询每个同学的分数
通过 学生id 和分数表中的学生id 再加上 课程id 和分数表的课程id 相等来筛选。
select student.name,course.name,score.score
from student, course,score
where student.id = score.student_id
and course.id = score.course_id;
join on
假设我们要查询许仙的成绩
select student.name,score.score,score.course_idfrom student,score where student.id = score.student_idand name = '许仙';
我们还可以通过join on达到同样的效果
select student.name,score.score,score.course_idfrom student join scoreon student.id = score.student_id and name = '许仙'
既然两种写法,没有本质的区别,为啥有两种写法呢?
只不过是在当前列子里没有区别而已
但是在别的场景中,join on 可能会和 from 多个表 where 的写法有本质的区别。
from 多个表 where 写法,仅仅是 内连接
join on 这样的写法,既可以表示 内连接,还可以表示 左外连接和右外连接
1.内连接
语法:
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件;
select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其他条件
我们创建学生表和分数表
create table student (id int primary key auto_increment,name varchar(20));
create table score (studentId int,score int);insert into student values(null,'张三'),(null,'李四'),(null,'王五');insert into score values(1,90);insert into score values(2,80);insert into score values(4,70);
查询学生的成绩
select student.name,score.score
from student join score on student.id = score.studentId;
内连接其实就是取出两个表中数据的交集
2.外连接
外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完全显示我们就说是右外连接
语法:
-- 左外连接,表1完全显示
select 字段名 from 表名1 left join 表名2 on 连接条件;
-- 右外连接,表2完全显示
select 字段 from 表名1 right join 表名2 on 连接条件;
左外连接:最终查询结果,是join左侧的表为主,会尽可能的把左侧的表的所有信息都体现出来
select student.name,score.score
from student left join score on student.id = score.studentId;
右外连接:和左外连接类型,是以 join 侧的表为主,尽可能把右侧的每个信息都体现出来
select student.name,score.score from student right join score on student.id = score.studentId;
全外连接:MySQL是不支持全外连接的
3.自连接
自连接就是一张表,自己和自己做笛卡尔积。
SQL比较方便可以进行列和列的比较,但是不方便进行 行和行之间的比较。
就比如上面那个分数表的例子,不同科目的分数是以行的方式来展示的
显示所有“计算机原理”成绩比“Java”成绩高的成绩
针对这个行和行比较,咱们不好搞,就转换成列和列比较,就是使用自连接来进行转换。
在进行自连接的时候,需要先给表起别名,否则就会报错,as是可以省略
select * from score as s1,score as s2;
再加上 student_id 的条件,筛选数据,期望把同一个学生的信息分别放到左右两侧
select * from score as s1, score as s2where s1.student_id = s2.student_id and s1.course_id = 1 and s2.course_id = 3;
最后
select * from score as s1, score as s2 where s1.student_id = s2.student_id and s1.course_id = 1 and s2.course_id = 3and s1.score < s2.score;
三、子查询
子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询
- 单行子查询:先执行一个查询,这个查询返回一条记录,以这个返回结果作为另一个查询的条件,进行最终查询。
代码示例:查询 张飞的同班同学
如果不用子查询
select classes_id from student where name = '张飞';
select name from student where classes_id = 1;
如果采用子查询,只需要一条代码
select name,classes_id from student where
classes_id=(select classes_id from student where name = '张飞');
- 多行子查询:子查询返回的数据不只是一条了,会有多条记录
当我们要查询语文或者Java的课程信息,如果用多条SQL
select id from course where name = '语文' or name = 'Java';
select * from score where course_id = 1 or course_id = 4;
使用子查询也能达到同样的效果
select * from score where course_id in (select id from course where name = '语文' or name = 'Java');
EXISTS关键字
使用 exists 关键字也可以进行子查询,也是对应子查询返回多条记录的情况
select * from score where exists (select score.course_id from course where(name = '语文' or name = 'Java') and course.id = score.course_id);
也能达到同样的效果
exists 工作过程:
先执行外层查询,需要遍历表中的每个记录(遍历score表的每个记录)
拿着当前这条记录,执行子查询。
这个写法中,子查询执行的次数,和外层表的行数是一样多的(执行效率相当低,执行SQL的次数太多了)
而在前面的in写法中子查询只执行一次(执行效率高,但是占用更多内存,会把子查询的结果都放到内存中)
如果外层查询的表很大,里层查询的表很小,适合用in(里层表小,内存占用就少)
如果外层查询的表很小,里层查询的表很大,适合用 exists(里层查询得到的结果太多了,内存放不下,此时就不能用 in了)
当然内外层都很大的话就都别用了吧,老老实实拆成多条语句吧
四、联合查询
在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all。使用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”的课程,不会去掉结果集中的重复
select * from course where id<3union allselect * from course where name='Java';
union 和 or 相比,主要的优势就是可以跨多个表进行数据合并
总结
- 在写复杂SQL的时候尽量不要一部到位,最好拆拆成多条SQL
- 实际开发尽量少用子查询,套娃太多可读性会比较差
- 多表查询效率较低,如果表的数量过多效率是非常低的。
聚合查询+联合查询+子查询相关推荐
- Oracle数据库:子查询、单行子查询,多行子查询,in,any,all语句,子查询的练习案例
Oracle数据库:子查询.单行子查询,多行子查询,in,any,all语句,子查询的练习案例 2022找工作是学历.能力和运气的超强结合体,遇到寒冬,大厂不招人,可能很多算法学生都得去找开发,测开 ...
- server多笔记录拼接字符串 sql_第四章、SQL Server数据库查询大全(单表查询、多表连接查询、嵌套查询、关联子查询、拼sql字符串的查询、交叉查询)...
4.1.查询的类型 declare @value as int set @value = 50 select 'age:'as age,2008 years,@valueas va --这种查询时跟 ...
- mysql子查询教行子查询_MySQL中列子查询与行子查询操作的学习教程
MysqL 列子查询及 IN.ANY.SOME 和 ALL 操作符的使用MysqL 列子查询 列子查询是指子查询返回的结果集是 N 行一列,该结果通常来自对表的某个字段查询返回. 一个列子查询的例子如 ...
- 【SQL查询系列】子查询经典案例
文章目录 前言 数据库 查询案例 1. 查询工资最低的员工信息: last_name, salary 2. 查询平均工资最低的部门信息 3. 查询平均工资最低的部门信息和该部门的平均工资 4. 查询平 ...
- 【SQL】(task3)复杂查询(视图 | 子查询 | 谓词 | Case)
学习总结 (1)视图和子查询.对于一些复杂的查询需要使用子查询加一些条件语句组合才能得到正确的结果.一个SQL语句的层数不能过深,不然可读性差而且执行效率也难以保证,所以尽量有简洁的语句来完成需要的功 ...
- ylb:子查询(嵌套子查询)和子查询(相关子查询)
ylbtech-SQL Server:SQL Server-子查询(嵌套子查询)和子查询(相关子查询) SQL Server 子查询(嵌套子查询)和子查询(相关子查询). 1,ylb:1,子查询(嵌套 ...
- oracle子查询子查询,Oracle 单行子查询和多行子查询
--什么是单行子查询? --从子查询中返回一行结果的查询 select e.employee_id,e.last_name,e.salary from employees e where e.depa ...
- order by 子查询_视图,子查询,标量子查询,关联子查询
视图 子查询 标量子查询 关联子查询 如何用SQL解决业务问题 各种函数 1. 视图 视图内存放SQL查询语句,运行时运行该语句.查出的数据为临时数据 创建视图 create view as 视图名称 ...
- Oracle 数据库的子查询(关联子查询)
文章目录 一.子查询结果返回一个值(单列单行) 二.子查询结果返回多行(单列多行) 三.子查询结果返回多列多行 四.关联子查询 (一)子查询执行顺序 (二)exists 关键字 五.子查询总结 六.关 ...
- 三、MySQL子查询学习笔记(标量子查询、列子查询、行子查询、表子查询 详解)
三.MySQL子查询学习笔记 7:子查询 含义: 一条查询语句中又嵌套了另一条完整的select语句,其中被嵌套的select语句,称为子查询或内查询:在外面的查询语句,称为主查询或外查询 分类: 一 ...
最新文章
- 静态路由_【零基础学云计算】静态路由!静态路由!静态路由!原理与配置
- TabHost中使用startActivityForResult无法接收返回值的解决方案
- 嵌入式linux启动过程分析,嵌入式Linux裸机开发(二)——S5PV210启动过程分析
- Go使用simple-json解析json数组字符串:以Harbor获取镜像tag为例
- V8 Promise源码全面解读
- product text的language dropdown list里 没有对应语言的问题
- LibLinear(SVM包)使用说明之(三)实践
- Coinbase在苹果应用商店前100免费应用中排名第30位
- 我们应该如何(以及为什么)要将Typescript与Express、nodejs一起使用(译文)
- mssql sql server 其它系统函数 parsename 点语法字符串分割函数应用简介
- vue如何设置视频封面_vue设置视频封面教程 vue如何修改标题
- 金山词霸2005开启后导致桌面刷新的问题
- 如何修复Win10下的 flashplayer?
- 基于 mini2440 电阻式触摸屏(一):电阻式触摸屏工作原理
- 2021年国内PT站点汇总(中英文名称对照表)很全呦!
- 怎么解决联想笔记本电脑待机后黑屏无法唤醒
- html表单按钮底部居中,Ant design StepsForm中如何使底部按钮居中
- 清空Github仓库方法
- linux查看当前文件和文件夹大小
- 数据库分析之逻辑结构设计
热门文章
- Java JDBC 使用Statement 产生sql注入问题
- AI时代已经到来,80%的程序员将无路可去
- word中mathtype和文字高度不一样
- 杨老师带你分析 过滤器、监听器和拦截器的区别
- android os能删掉那,安卓手机里的那些英文文件夹到底都是啥?可不可以删除?...
- 验证身份证信息(python)
- 青春日志html,伤感青春日志语录
- linux spi 工作模式,嵌入式linux系统的开发——SPI Bit-banging方法的实现
- 装Ubuntu系统时显示“输入不支持”的一种解决方案
- tinyumbrella java_tinyumbrella打不开