MySQLMySQL表之联合查询(多表查询)
Posted 恒等于C
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQLMySQL表之联合查询(多表查询)相关的知识,希望对你有一定的参考价值。
📌前言:本篇博客介绍mysql数据库的MySQL表之联合查询(多表查询),学习MySQL之前要先安装好MySQL,如果还没有安装的小伙伴可以看看博主前面的博客,里面有详细的安装教程。
那我们废话不多说,直接进入主体!🚀🚀🚀
MySQL表之联合查询(多表查询)
一.联合查询
然后就到联合查询,所谓联合,就是把多个表的记录往一起合并,一起进行查询,也叫多表查询。多表查询是整个sql
中最复杂的部分,也是笔试中爱考的部分,但是实际开发中一般禁止使用多表查询。
- Tip📣:虽然多表查询是笔试中爱考的部分,但在实际工作中截然不同,就所谓面试造核弹,工作拧螺丝~
1.笛卡尔积
📌多表查询中的核心操作,就是笛卡尔积,笛卡尔积的计算非常简单,就类似于排列组合,笛卡尔积是针对任意两张表之间进行的运算。
比如:
再比如:
图中的就是笛卡尔积的运算过程:
- 先拿第一张表的第一条记录,和第二张表的每个记录,分别组合,得到一组新的数据。
- 然后继续再拿第一张表的第二条记录,重复刚刚的操作。
- 最后形成的所有新的数据,就是我们的笛卡尔积。
所以针对A
B
两张表,得到的笛卡尔积,此时笛卡尔积的列数,就是A的列数+B的列数,笛卡尔积的行数,就是A的行数 * B的行数
。所以在实际工作中,公司的数据量非常大,那么进行多表查询的时候就很可能把数据给搞挂了,所以就直接一刀切,禁止多表查询这种危险性较大的操作。
上述操作我们在MySQL中操作一下:
先创建好student
和class
表:
mysql> create table student(studentId int,name varchar(50),classId int);
insert into student values(1,'张三',1);
insert into student values(2,'李四',1);
insert into student values(3,'王五',2);
insert into student values(4,'赵六',2);
mysql> create table class(classId int,name varchar(20));
insert into class values(1,'java1班');
insert into class values(1,'java2班');
创建好之后我们查询一下确认没错:
然后就是我们的笛卡尔积,在SQL中进行笛卡尔积,最简单的做法就是直接select from后面跟上多个表名,表名之间用逗号分割。
mysql> select * from student,class;
可以看见,笛卡尔积是两张表中数据尽可能排列组合得到的,在这些排列组合中,有一些数据是我们需要的,有一些是没有意义的。也就是说,笛卡尔积是一个单纯无脑的排列组合,这些组合不一定都有意义。
像两张表中,classId这一列相等的才是我们需要的数据,对于这样的相等条件,就称为“连接条件”。带有连接条件的笛卡尔积,其实就是"多表查询"了。如果笛卡尔积中两个列的名字相同,在写条件的时候可以通过表名.列名
的格式来访问,如果列名不会混淆,也就是两个列名条件不同名的话,可以通过表名.列名
访问,也可以省略表名。
如:
在查询两张表后加入where连接"连接条件"。
然后我们看到还是有一些其实我们不需要的数据,在实际查询中,我们需要的数据往往只有几列,所以我们在查询的时候可以不用select *
,而是select 我们需要的那几列。如我们下面的表只想看学生对应班级名。
如:
2.创建查询例子表
然后我们学习一下各种查询,在学习这些查询之前,为了更好的说明和了解这些查询,我们先创建下列几个表,让大家更容易理解各类查询:
- 📕classes班级表
mysql> create table classes(id int primary key auto_increment, name varchar(20), `desc` varchar(100));
insert into classes(name, `desc`) values
('计算机系2019级1班', '学习了计算机原理、C和Java语言、数据结构和算法'),
('中文系2019级3班','学习了中国传统文学'),
('自动化2019级5班','学习了机械自动化');
- 📙student学生表
mysql> create table student (id int primary key auto_increment, sn varchar(20), name varchar(20), qq_mail varchar(20) , classes_id int);
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','tellme',null,2),
('09527','老外学中文','foreigner@qq.com',2);
- 📗course课程表
mysql> create table course(id int primary key auto_increment, name varchar(20));
insert into course(name) values
('Java'),('中国传统文化'),('计算机原理'),('语文'),('高阶数学'),('英文');
- 📒score分数表
mysql> create table score(score decimal(3, 1), 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),
//好好说话
(56, 6, 2),(43, 6, 4),(79, 6, 6),
//tellme
(80, 7, 2),(92, 7, 6);
创建好之后我们一一查询一下:
实际上,在这个场景中,涉及到的主体有三个,学生,班级和课程,学生和班级是一对一的关系,学生和课程是多对多的关系,而分数表,就是学生和课程之间的关联表。
下面正式开始介绍我们的联合查询中的各种查询~
3.内连接
我们用案例来学习我们的查询,首先登场的是内连接查询,这种查询是比较常用的查询,也是我们上面有了解过的查询。
例子1
:查询“许仙”同学的成绩
📌第一步:查表
首先我们要想到,查询某位同学的成绩,所用到的表应该是哪些,这里是学生表和成绩表,所以我们查询的应该是学生表和成绩表,最简单的联合起来就是在select的时候用逗号连接两个表,比如select * from student,score;
我们看一下查询结果(此处省略n行):
可以看到我们查询的数据有160行那么多,我们仔细观察发现,虽然我们查询的是两张表的结果,但是查询结果的表是合并的,也就是说如果我们没有用上一些条件的话,查出来的表就相当于排列组合出来的无效数据了,所以我们要在查询多张表时应该有一个匹配的数据作为桥梁。
📌第二步:确定条件
我们把学生表和成绩表拿下来,发现他们的学生id是一样的,所以我们可以在查询这两张表的时候用id作为配对条件,这时候用我们之前学过的where子句就可以啦。
📌第三步:查询结果
最后查询得到的就是一张对应学生对应成绩的表了,然后我们题目写的是要得到许仙同学的成绩,所以我们再筛选名字为许仙的就可以啦:
这便是我们其中一种内连接,也就是用条件匹配来联合多张表,我们还有一种内连接的写法是用join...on
,其实都差不多,前面的是用逗号和where连接查询两张表,这里就用join...on
连接,如下面的写法的查询结果是和上面一样的:
select * from student join score on student.id = score.student_id and student.name = '许仙'
内连接:
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件;
select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其他条件;
例子2:
查询所有同学的总成绩,及同学的个人信息
同样的先看一下总成绩和个人信息需要用到的表,然后连接两张表,条件是id相同,以及需要的是同学的个人信息,当然这里还有总成绩需要排序后计算和,所以我们就可以写出查询:
select student.sn,student.name,student.qq_mail,sum(score.score) from student,score where student.id = score.student_id group by student_id;
查询结果:
像这样的多表查询,看起来比较复杂,按顺序多写几遍就可以得到规律,很流畅的就写出来了。比如这里的查询的是同学信息和总成绩,使用的表是学生表和成绩表,条件是id相同,总成绩需要排序计算。
例子3:
查询所有同学的各科成绩
这里的话同样是先分析一下,查询的是各科成绩,需要用到的表是学生表,成绩表还有课程表,那么三个表联合的时候也一样,只要条件匹配就可以很好的连起来。
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
来实现,可以写成下面的样子:
from 表1 join 表2 on 条件 join 表3 on 条件
但是这种内连接的形式,我们还是推荐使用where子句,那join有什么用呢,这就到我们另一个连接,也就是外连接了。
4.外连接
join...on
能够做到上面写法做不到的事情,也就是外连接。
📌定义:外连接分为 左外连接 和 右外连接 。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完全显示我们就说是右外连接。
例表创建:
//学生表
mysql> create table student2(id int,name varchar(50),classes_id int);
insert into student2 values(1,'张三',1);
insert into student2 values(2,'李四',1);
insert into student2 values(3,'王五',2);
insert into student2 values(4,'赵六',3);
//班级表
mysql> create table class(id int,name varchar(50));
insert into class values(1,'java1班');
insert into class values(,'java2班');
那么外连接是什么意思呢,我们同样用查询来说明一下,我们先看看这里的学生表和班级表的内容:
当我们学生表中有班级编号是3的同学,但是班级表却没有的时候,如果使用内连接时,就会省略掉班级编号为3的同学,比如我们现在使用内连接:
查询结果:
mysql> select student2.name,class.name from class,student2 where student2.classes_id = class.id;
+--------+----------+
| name | name |
+--------+----------+
| 张三 | java1班 |
| 李四 | java1班 |
| 王五 | java2班 |
+--------+----------+
上面的这种写法就相当于inner join,所以当我们需要保存其中一张表的完整性的时候,我们就用到了外连接,这里的左外连接和右外连接的意思就是,左外就是保留左边的完整性,右外就是保留右边的完整性。也就是说左外链接的时候就会以左侧的表为主,尽可能的把数据都列出来,大不了后侧表对应列变成null。
语法:
- 左外连接,表1完全显示 select 字段名 from 表名1 left join 表名2 on 连接条件;
- 右外连接,表2完全显示 select 字段 from 表名1 right join 表名2 on 连接条件;
例子(当连接中为保留表的完整性就会在没有数据的地方加入null):
mysql> select student2.name,class.name from student2 left join class on student2.classes_id = class.id;
+--------+----------+
| name | name |
+--------+----------+
| 张三 | java1班 |
| 李四 | java1班 |
| 王五 | java2班 |
| 赵六 | NULL |
+--------+----------+
这就是外连接。
也就是说,内连接就是包含两个表中同时拥有的记录,而外连接中,左外连接是以左侧表为主,左侧表中的每个记录都会在左外连接中有体现,右外连接则是以右侧表为主,每个记录在右外连接都有体现,那么有没有既包含左侧表又包含右侧表的"全外连接"呢,答案是mysql不支持!
5.自连接
📌自连接是指在同一张表连接自身进行查询。
我们可以继续使用上面的成绩表和课程表来给大家说明,为了可观我们先把表拿下来:
mysql> select * from course;
+----+--------------------+
| id | name |
+----+--------------------+
| 1 | Java |
| 2 | 中国传统文化 |
| 3 | 计算机原理 |
| 4 | 语文 |
| 5 | 高阶数学 |
| 6 | 英文 |
+----+--------------------+
6 rows in set (0.00 sec)
mysql> select * from score;
+-------+------------+-----------+
| score | student_id | course_id |
+-------+------------+-----------+
| 70.5 | 1 | 1 |
| 98.5 | 1 | 3 |
| 33.0 | 1 | 5 |
| 98.0 | 1 | 6 |
| 60.0 | 2 | 1 |
| 59.5 | 2 | 5 |
| .... | ..... | .... |
+-------+------------+-----------+
(省略了后面部分数据)
20 rows in set (0.00 sec)
我们依然用例题的方式来理解:
例子:显示所有"计算机原理"成绩比"Java"成绩高的成绩信息
首先我们要知道这里的是成绩比较,而成绩都在成绩表中,所以应该是用自连接来查看自己,但是这里涉及到两个科目,所以需要一些课程表的信息,但需要的不多,所以没必要也连接课程表,我们只需要知道这两个科目在成绩表中的id就行。
第一步:查看两个科目在成绩表中的course_id
select id,name from course where name = 'Java' or name = '计算机原理';
第二步:发现id是1和3,我们就可以在成绩表中自连接查询了
mysql> 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;
这里的意思是查询成绩表中,s1代表id为1的科目,s2代表id为3的科目,查询其中学生id一样并且s1成绩小于s2的,显示s1的所有信息,也就是成绩低那一科的信息。这里就是用自连接的方式去显示,同样也可以用join on 去写。
🚩以上便上MySQL表之联合查询(多表查询),欢迎关注。一起学习,共同努力!
还有一件事:
mysql多表联合查询并且可以补充没有的数据
有两张表a 与表b,
其它表b.id与a.uid关联,我现在使用selcet * from a,b where (b.id=a.uid)
这里因为有这个相等的条件存在,这个查询会因为b表中的id不存在,而不能显示a.uid的表记录。我想显示出表a 与表b的关系,如果b.id记录不存在,自动用null代替,如果操作呢?
以上是关于MySQLMySQL表之联合查询(多表查询)的主要内容,如果未能解决你的问题,请参考以下文章