多表查询

**交叉连接 cross join
内连接 inner join
外连接 
左连接 left join
右连接 right join
联合查询 UNION
全连接 **

1、多表纵向合并

纵向合并需要注意的是,两张合并的表查询结果的字段数必须一致,

MariaDB [hellodb]> select stuid,name from students
    -> union 
    -> select tid,name from teachers;

查询结果
MYSQL-多表查询_第1张图片
我们尝试将第二张表中的name,tid查询的顺序反过来试一下

MariaDB [hellodb]> select stuid,name from students
    -> union 
    -> select name,tid from teachers;

查询结果
MYSQL-多表查询_第2张图片

总结:

    我们发现纵向合并对字段的类型并不严格,只要与第一张表的字段数是相同的就可以,当然,第二个查询的结果显示然是没有意义的。
    在别的数据库中,例如orcal或serverSQL会报错,因为类型不符。

2、union的去重功能

查看teachers表
MYSQL-多表查询_第3张图片
重新构建一个与teachers表相似的表
create table teachers2 select * from teachers where tid>=3;
MYSQL-多表查询_第4张图片
添加数据

insert teachers2 (tid,name,age,gender)values(5,'linux',22,'m');
insert teachers2 (tid,name,age,gender)values(6,'Python',22,'m');

MYSQL-多表查询_第5张图片
将两张表连接起来再次查看
MYSQL-多表查询_第6张图片

总结:

    union本身亦可以去重,当然这里只是示范一下,还有个命令可以直接去重
    select distinct * from teacher2 可以在自己表中去掉重复的行 

CROSS JOINS

首先,我们之前利用union 进行了纵向连接,那么,我们可不可以横向连接呢?当然是可以的,纵向连接由字段数量的限制,而横向连接是没有字段的限制的,比如:
创建两个表
t1表

MYSQL-多表查询_第7张图片
t2表
MYSQL-多表查询_第8张图片
接下来我们直接最者两张表进行cross join 连接,
select * from t1 cross join t2;
MYSQL-多表查询_第9张图片

首先,第一张表的第一条记录和第二张表的每条记录进行整合,这就有了15条记录。在数据库中百万级别的表才算有点规模,假如真的这样做了,无疑是灾难性的。其次,这样将两张表连接起来是没有意义。所以,我们使用内连接来进行连接,找出对应两张表的关联性,设定条件进行连接查找。

1、内连接

MYSQL-多表查询_第10张图片

关键字: inner join
说明:
两张表,分别是students表和teachers表,students表中存放的teacherid字段,记录了每个学生的负责的老师,teachers表中记录了老师的id。所以,我们将这个作为条件。

MariaDB [hellodb]> select * from 
    -> students inner join teachers
    -> on  条件 等价于 where 
    -> students.teacherid=teachers.tid;
    由于是跨表查询,所以,必须指明哪个表下的字段,否则系统无法识别来源

查询结果
MYSQL-多表查询_第11张图片
但是,我们发现有两个字段完全一样,所以,我们可以选择留下一个指明信息

select  对字段定义别名
    stuid,s.name as studentname ,s.age as studentage tid
    t.name as teachername ,t.age as teacherage
    from 
    students as s   对表定义别名
    inner join      连接
    teachers as t   定义别名
    on              条件  
    s.teacherid=t.tid;    

查询结果
MYSQL-多表查询_第12张图片

2、左外连接

MYSQL-多表查询_第13张图片
说明:
看图可以看出来,我们只需要A的所有记录,B表中与A表关联的数据

MariaDB [hellodb]> select
    -> stuid,s.name,tid,t.name
    -> from
    -> students as s 
    -> left outer join
    -> teachers as t
    -> on
    -> s.teacherid=t.tid;

查询结果
MYSQL-多表查询_第14张图片

3、右外连接

MYSQL-多表查询_第15张图片
说明:
与上面相反

MariaDB [hellodb]> select
    -> stuid,s.name,tid,t.name
    -> from
    -> students as s
    -> right join 
    -> teachers as t
    -> on
    -> s.teacherid=t.tid;

查询结果
MYSQL-多表查询_第16张图片

4、左外连接 扩展

MYSQL-多表查询_第17张图片
说明:
我们现在需要的是查询A表与B表没有交集的那部分,
依旧是两张表,students and teachers 表,这两张表有交集的地方就是学生表的teacherid和老师表的tid。
所以,teacherid 是空的就是我们所要找的

查询结果
MYSQL-多表查询_第18张图片

5、右外连接 扩展

MYSQL-多表查询_第19张图片

说明:
与上相反

MariaDB [hellodb]> select 
    -> stuid,s.name,teacherid,
    -> tid,t.name 
    -> from
    -> students as s
    -> left join
    -> teachers as t
    -> on 
    -> s.teacherid=t.tid    对有关联的查询结果再次进行过滤
    -> where
    -> stuid is null;

查询结果
MYSQL-多表查询_第20张图片

6、完全外连接

MYSQL-多表查询_第21张图片

说明:
这里需要说明的是,A表和B表所有的内容都要,但是,这不和cross join一样,cross join 是可以将两个完全没有联系的表横向合并。
这里不一样,A表和B表进行横向合并,但是如果A表和B表有相同点,那么久合并在一起,如果没有,就单独记录,并且补空
热切我们发现,这个似乎是左外连接和右外连接的结合,所以,我们可以使用union

如图
MYSQL-多表查询_第22张图片

select * from students left join teachers 
on 
students.teacherid=teachers.tid 
union 
select * from students right join teachers 
on 
students.teacherid=teachers.tid;

查询结果
MYSQL-多表查询_第23张图片

7、子查询

MYSQL-多表查询_第24张图片

说明:
所谓子查询,就是select执行后的结果,被其他SQL调用
举个例子
以students表为例,计算所有学生的平均年龄
select avg(age) from studetns;

MYSQL-多表查询
现在我们要查询所有小于平均年龄的学生

select * from students where age < (select avg(age) from students)
;

查询结果
MYSQL-多表查询_第25张图片
现在我们接着上图中的问题:

select * from
(
select 
s.stuid,
s.name s_name,
s.teacherid,
t.tid,
t.name t_name
from
 students s 
 left outer join
 teachers t  on 
 s.teacherid=t.tid
 union
 select s.stuid,
 s.name,
 s.teacherid,
 t.tid,
 t.name
 from
 students s 
 right outer join 
 teachers  t 
 on 
 s.teacherid=t.tid
)
as a
 where 
 a.teacherid is null 
 or
  a.tid is null;

查询结果
MYSQL-多表查询_第26张图片

8、自连接

说明:
首先,我们创建一张员工表表,表中存放着id,员工姓名,领导ID。

create table employee
(
id int,
name char(10),
leader_id int    
);
插入信息
insert employee values(1,'A',null);
insert employee values(2,'B',1);
insert emplyee values(3,'C',2);
insert emplyee values(4,'D',3);

结果如下
MYSQL-多表查询_第27张图片
假设,我们要查询每个员工的上级领导ID,该怎么查。
我们可以将这一张表想成两张表,分别为A表和B表,

MYSQL-多表查询_第28张图片

    我们要查询的是第一张表的NAME和第二张表的上级的NAME,我们发现,A表的TID和第二张表的ID是关联的,
    当我们查询1号员工的TID的时候,由于1号员工的TID是null,所以,我们要显示的上级NAME是NULL,
    当我们查询2号员工的上级ID时,当A表的TID等于B表的ID的时候,条件达成,显示B表的姓名。以此类推 
select A.name as employee_name,B.name as leader_name
from
employee as A left join employee as B
on
A.leaderid=B.id;

查询结果
MYSQL-多表查询_第29张图片

9、三表查询

    说明:
    假设我们有两张表,学生表和课程表
    学生表存放的是:
    stu_id,stu_name,stu_cassid
    课程表中存放的是:
    cours_id, cours_name
    在数据库中,有很多逻辑结构,一对一,一对多,多对多。结合实际情况,我们一个学生可能同时学习多个课程,每个课程可能有好多学生学,所以,由此可以看出是多对多的关系,
    要实现多对多,在数据库中我们可以创建第三个表来实现,
    第三张表中存放的是
    id,stu_id,cours_id,score
    但是这个两个字段显然都不合适做主键,所以,就可以添加一个字段ID做主键。再添加一个score字段,存放课程成绩

我们最终要实现的是某个学生在某个课程上考试成绩是多少

第一步:首先我们实现两张表来进行查询,这样条理会清晰很多

实现:
查询学生表中学生和成绩表中所有学生对应的考试成绩,展示不考虑课程ID。当学生表中的stuid等于成绩表中的stuid的条件达成,我们就显示学生姓名,考试成绩

说明:
我们只查询两张表中共有交集的部分,如下图

MYSQL-多表查询_第30张图片
好像似曾相识,

MariaDB [hellodb]> select stu.name,sc.score 
    -> from
    -> students as stu 
    -> inner join
    -> scores as sc
    -> on
    -> stu.stuid=sc.stuid;

查询结果
MYSQL-多表查询_第31张图片

第二步:这次我们实现的是某个课程的对应成绩

    说明;
    我们暂时不考虑学生表中的信息,只查询成绩表和课程表,
    只取两个表的交集部分,依旧还是使用inner join
MariaDB [hellodb]> select course.course,sc.score
    -> from
    -> scores as sc
    -> inner join
    -> courses as course
    -> on
    -> course.courseid=sc.courseid;

查询结果
MYSQL-多表查询_第32张图片

第三步:将以上两个步骤连接起来,就达到了我们的要求

    说明:
    我们要实现的是某个学生的某个课程对应的成绩,
    我们对比两张表,发现,我只要把第一步的查询结果与第二张表的查询结果联合在一次就达到了我们的最终要求。   

MYSQL-多表查询_第33张图片

当然,我们指定对应的字段就可以了
首先,我们再次查询第一步要实现的目的,这次我们不指定字段,这样看的清晰点

select * from 
students
inner join
scores
on
students.stuid=scores.stuid;
查询结果

MYSQL-多表查询_第34张图片

我们可以将查询出来的结果想象成一张独立的表,然后,我们将这张表中的courseid与课程表中的courseid相等作为条件,将课程名称取出来。
其实我们可以想象成双表查询,只要在取这两张表的交集即可

MariaDB [hellodb]> select
    -> stu.name as student_name,
    -> co.course as course_name,
    -> sc.score 
    -> from
    -> students as stu
    -> inner join
    -> scorses as sc
    -> on
    -> stu.stuid=sc.stuid
    -> inner join
    -> courses as co
    -> on
    -> sc.courseid=co.courseid;

查询结果
MYSQL-多表查询_第35张图片