您现在的位置是:首页 >学无止境 >MySQL表操作:提高数据处理效率的秘诀(进阶)(2)网站首页学无止境
MySQL表操作:提高数据处理效率的秘诀(进阶)(2)
?“学习难免有坎坷,重要的是你能尽力而为,持之以恒。”?
?作者:不能再留遗憾了?
?专栏:MySQL学习?
?本文章主要内容:MySQL表操作进阶:聚合查询和联合查询?
前言
前面我们学习了MySQL进阶的数据库约束、表的设计和新增,那么今天我将为大家分享MySQL表查询的进阶。如果大家觉得内容对你有用的话,不要忘记点个赞哦。
聚合查询
MySQL聚合查询是指将一组数据进行分组,并且对每组数据进行统计分析,从而得出汇总信息的查询方式。常见的聚合函数包括SUM、AVG、MAX、MIN、COUNT等,它们可以应用于分组后的数据,得出针对每组数据的汇总结果。使用聚合查询可以统计单个字段或多个字段的汇总信息。
聚合函数
MySQL内部提供了函数供我们来进行相关操作。
COUNT() | 返回查询到的数据的数量 |
---|---|
SUM() | 返回查询到的数据的 总和,不是数字没有意义 |
AVG() | 返回查询到的数据的 平均值,不是数字没有意义 |
MAX() | 返回查询到的数据的 最大值,不是数字没有意义 |
MIN() | 返回查询到的数据的 最小值,不是数字没有意义 |
create table exam_result (id int primary key auto_increment,name varchar(20),chinese decimal(3,1),
-> math decimal(3,1),english decimal(3,1));
insert into exam_result values (null,'张三',89.5,88.5,90.5),(null,'李四',92,94.5,98),(null,'王五',89,95,90);
select * from exam_result;
select count(name) from exam_result;
select sum(chinese + math + english) as total from exam_result;
select sum(math) as math_total from exam_result;
select avg(math) from exam_result;
select max(math) from exam_result;
select min(math) from exam_result;
我们知道,任何数和NULL进行计算得到的结果都是NULL,那么使用聚合函数的时候如果数据中有NULL,结果是什么呢?
insert into exam_result values (null,'赵六',null,null,null);
select sum(math) from exam_result;
我们可以看到,当使用聚合函数的数据中存在null时,是不影响最后数据的。
group by子句
SELECT 中使用 GROUP BY 子句可以对指定列进行分组查询。需要满足:使用 GROUP BY 进行分组查询时,SELECT指定的字段必须是“分组依据字段”,其他字段若想出现在SELECT 中则必须包含在聚合函数中。
select column1, 聚合函数(column2), .. from table group by column1,column3;
我们以公司内不同职位的员工工资为例,来看看group by是如何使用的。
create table employee (name varchar(20),post varchar(30),salary decimal(10,2));
insert into employee values ('张三','产品经理',9000.6),('李四','产品经理',12000),('王五','普通程序员',11000.88),
-> ('赵六','普通程序员',12000),('小花','普通程序员',11500.68),('小美','高级程序员',16000.89),('小帅','董事长',30500);
select * from employee;
select post,avg(salary) from employee group by post;
having 子句
当我们使用 group by 进行分组之后,可以使用 having 子句进行条件筛选,并且分组之后只能用having 子句,而不能使用 where 子句,where 子句只能在分组之前使用。
select post,avg(salary) from employee group by post having post != '董事长';
select post,avg(salary) from employee where post != '董事长' group by post;
是在分组之前使用where 子句条件筛选还是分组之后使用having 子句进行条件筛选,需要根据实际的需要来选择。
联合查询
MySQL联合查询(Union Query)是指将多个SELECT语句的结果集合并成一个结果集的查询方式。使用联合查询可以将多个查询的结果合并为一个结果集,方便比较和分析数据。
我们在日常生活中处理的数据往往是来自于不同的表,而要想对不同表中的数据进行处理就需要用到联合查询。联合查询是将多个结构大致相同的表进行笛卡尔积合并成一个表,然后通过条件子句筛选掉不合适的数据。
使用联合查询时,所有的SELECT语句需要满足以下几个条件:
1.所有的SELECT语句必须包含相同的列数
2.所有的SELECT语句中,被联合的列必须具有相同的数据类型和长度
3.结果集中的列的顺序必须相同,但列的别名可以不同
我们使用以下的数据来讲解联合查询。
create database test charset utf8;
use test;
create table classes (id int primary key auto_increment,name varchar(20),sub varchar(100));
create table student (id int primary key auto_increment,sn varchar(20),name varchar(20),classes_id int);
create table cource (id int primary key auto_increment,name varchar(20));
create table score (score decimal(3,1),student_id int,cource_id int);
insert into classes (name,sub) values
-> ('计算机系2019级1班', '学习了计算机原理、C和Java语言、数据结构和算法'),
-> ('中文系2019级3班','学习了中国传统文学'),
-> ('自动化2019级5班','学习了机械自动化');
insert into student(sn, name, classes_id) values
-> ('09982','黑旋风李逵',1),
-> ('00835','菩提老祖',1),
-> ('00391','白素贞',1),
-> ('00031','许仙',1),
-> ('00054','不想毕业',1),
-> ('51234','好好说话',2),
-> ('83223','tellme',2),
-> ('09527','老外学中文',2);
insert into cource (name) values
-> ('Java'),('中国传统文化'),('计算机原理'),('语文'),('高阶数学'),('英文');
insert into score(score, student_id, cource_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);
学生和班级之间是一对多关系
学生和课程之间之多对多的关系 score相当于关联表
班级和课程没关系
内连接
select 列名 from 表1 join 表2 on 连接条件 and 其他条件;
select 列名 from 表1,表2 where 连接条件 and 其他条件;
表名1,表名2 和 表名1 join 表名2就是将做两个表的笛卡尔积的操作。
假设我们需要查询许仙的成绩。
select * from student,score where id = student_id and name = '许仙';
因为两个不同的表的列名可能相同,所以可以使用 表名.列名 来区分。
select * from student,score where student.id = score.student_id and student.name = '许仙';
这里我们虽然找到了想要的结果,但是可以看出表中有些数据看起来很多余,所以我们可以只显示需要的列。
select name,score from student,score where student.id = score.student_id and student.name = '许仙';
多表查询一般步骤:
1.分析清楚需求中,涉及到的信息都在哪些表里
2.针对这多个表进行笛卡尔积
3.筛选出其中的有效数据
4.结合需求中的条件,进一步加强条件
5.针对列进行精简
当我们用 表名1 join 表名2 来做笛卡尔积时,后面的条件子句只能使用 on 来连接。
select name,score from student join score on student.id = score.student_id and student.name = '许仙';
当然我们在使用联合查询的时候还可以搭配着聚合查询使用。
查询许仙同学的总成绩。
select name,sum(score) as total from student join score on student.id = score.student_id and student.name = '许仙';
外连接
什么叫内连接?
内连接通过使用两个或多个表之间的共同列来连接这些表。内连接只返回两个表中共有的行,即只有在两个表中都存在的匹配行才会被返回,非匹配行将被忽略。也就是说一个表中的所有数据都会与另一个表中的数据匹配
什么叫外连接?
外连接可以返回两个表中所有的数据行,同时还会返回左表或右表中没有匹配到的数据行。外连接主要分为左外连接(left outer join)和右外连接(right outer join)两种。
左外连接会返回左表中的所有行,以及两个表中匹配到的行。如果右表中没有匹配到左表中的某些行,则会在查询结果中返回NULL值。与之相反,右外连接会返回右表中的所有行,以及两个表中匹配到的行。如果左表中没有匹配到右表中的某些行,则会在查询结果中返回NULL值。
-- 左外连接,表1完全显示
select 列名 from 表名1 left join 表名2 on 连接条件;
-- 右外连接,表2完全显示
select 列名 from 表名1 right join 表名2 on 连接条件;
插入一个classes中不存在的班级,然后显示每个学生的班级。
insert into student (sn,name,classes_id) values
('06258','张三',4);
select student.name,classes.id from student,classes where student.classes_id = classes.id;
这里我们看到,并未出现新加入的“张三”,因为classes中并没有id为4的班级,这就叫做内连接,那么要想显示出“张三”,就得使用外连接。
select student.name,classes.id from student left join classes on student.classes_id = classes.id;
也可以显示出所有的班级。
select student.name,classes.id from student right join classes on student.classes_id = classes.id;
自连接
自连接用于连接同一个表中的不同行。自连接可以用于在同一个表中寻找相关的数据行。
select 列名 from 表名 as 别名1,表名 as 别名2 where 条件;
select 列名 from 表名 as 别名1 join 表名 as 别名2 on 条件;
显示所有“计算机原理”成绩比“Java”成绩高的成绩信息
因为这里不同学科的成绩属于不同行,我们平时进行的比较是列于列之间的,那么要想将一个表中的行与行之间进行运算,就需要用到自连接,自连接就相当于把行转换为列。
select * from score s1,score s2 where s1.student_id = s2.student_id and s1.cource_id = 1
-> and s2.cource_id = 3 and s1.score < s2.score;
显示出名字
select stu.name,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 cource c1 on s1.cource_id = c1.id
-> join cource c2 on s2.cource_id = c2.id
-> and s1.score < s2.score
-> and c1.name = 'Java'
-> and c2.name = '计算机原理';
因为需要进行笛卡尔积,所以自连接的代价较大,如果数据量过大,需要慎重考虑。
子查询
MySQL的子查询指的是在一个查询语句中嵌套了另一个查询语句。子查询通常用于在查询过程中筛选出满足某些条件的行,然后再将这些行与外层查询语句中的其他数据进行处理。
子查询有两种类型:标量子查询和表子查询。标量子查询返回的结果是一个单一的数据值,而表子查询返回的结果是多行多列的数据集。子查询嵌套的深度可以很深,但会导致查询效率变慢。
查询与“不想毕业”同学的同班同学。
首先我们需要知道“不想毕业”同学的班级,然后将同一班级的人给筛选出来。
select classes_id from student where name = '不想毕业';
select name from student where classes_id = 1;
?单行子查询(标量子查询)
通过子查询,我们可以这样写。
select name from student where classes_id = (select classes_id from student where name = '不想毕业');
??多行子查询(表子查询)
查询“语文”或“英文”课程的成绩信息
select * from score where cource_id in (select id from cource where
-> name='语文' or name='英文');
这里使用子查询的代码可读性不高,并且当嵌套层数太多时可能会出现严重的后果,所以不是很建议大家使用。
合并查询
MySQL的合并查询(union)是一种在多个查询结果中获取不同数据行并将它们整合成一个查询结果集的查询方式。合并查询需要满足一定的条件,比如数据行必须具有相同的列数和数据类型,并且必须按照相同的顺序排列。
合并查询通常用于需要从多个表或查询结果中获取数据的查询需求。合并查询分为两种类型:UNION和UNION ALL。UNION去重并合并查询结果,而UNION ALL只是简单地合并查询结果。
查询id小于3,或者名字为“英文”的课程
select * from cource where id < 3 or name = '英文';
使用联合查询
select * from cource where id < 3 union (select * from cource where name = '英文');
or只能针对一个表进行查询,union可以针对多个表进行查询
union会自动去重,union all不会去重