天天看点

MySQL DQL操作之高级查询(多表查询篇)

1.高级查询的分类

多表关联查询(包括内连接,外间接和自然连接)

子查询

联合查询(union和union all)

2.多表关联查询

定义:

所谓的多表关联查询即指:多张表进行联合查询。当然这些表可能一样,也可能不一样。说一样指的是多次对自身查询。

多表关联查询的分类:

内连接

自然连接

外连接

1) 内连接

两表进行内连接,即两张表通过关联字段进行连接,非公有字段进行拼接,而对于公有字段即关联字段,则是取其中一张表的,然后记录取的是关联字段值在两表中都有的记录。

在解释内连接之前首先看一个数学中的概念:笛卡尔积

参见百度:

两个集合X和Y的笛卡尓积(Cartesian product),又称直积,表示为X × Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员

上述表达的意思大概如图所示:

MySQL DQL操作之高级查询(多表查询篇)

然后用SQL的表示形式如下:

数据准备:

emp员工表:

MySQL DQL操作之高级查询(多表查询篇)
dept部门表:
MySQL DQL操作之高级查询(多表查询篇)

放上SQL执行:

执行结果如下:(总记录数:56条)

MySQL DQL操作之高级查询(多表查询篇)

我们发现总记录数是:56条即14*4=56条,显然是直接交叉连接得到结果,数据本身没什么问题,但是按照实际的情况:一个员工(比如我们的7369号员工)应该在20号部门才对,但是结果中却是多个,而且还是所有部门的都有,显然不符合实际情况。

分析原因:

我们没有对这两个表建立关联,即一个员工应该关联对应的部门,也就是说我们需要通过deptno把两表连接起来,通过员工的deptno在dept部门表中去找对应的部门才对,对此有两种解决方案:其一,给定where条件让两张表的deptno保持一致,即现在的内连接;其二,通过emp员工表的deptno去关联dept部门表的deptno字段,即下文即将提到的外连接。

现在我们通过内连接方式去关联两表,以期解决上述问题:

先放上SQL:

-- 形式1
select * from emp,dept where emp.deptno=dept.deptno;
           

再来看看结果:

MySQL DQL操作之高级查询(多表查询篇)

分析:

很明显的,数据记录条数减少了很多,后面的deptno两表都是一一对应的,这样我们就把那些脏数据去除掉了,这才是我们要的数据。

其实上述SQL还不是内连接的标准形式,标准形式如下:(inner join … on)

-- 形式2 (标准)
select * from emp inner join dept on emp.deptno=dept.deptno;
           

另外一种专门针对等值的内连接语法格式:

-- 形式3(限制)
select * from emp inner join dept using(deptno);  -- 等值连接  
           

结论:

当我们需要对两表进行联查时,如果我们需要两表的数据和实际相符合,我们可以通过公共的字段把两张表关联起来即通过where条件限制起来。或者使用内连接标准的形式,采用inner join …on。但是现在有一个问题是,部门表里面的40号部门没有员工,但是我需要看到,但是这里却没有显示。究其缘由,主要是内连接是通过关联字段进行连接,只取两表公有的记录得合并记录。

于是就出现了接下来将为大家呈现的是外连接的解决方案

练习:

2) 外连接

定义:所谓的外连接,即以其中一张表为主表,去关联从表,结果的生成是根据主表的记录关联字段来限定的,即拿着主表的关联字段去从表中去查,查到就进行关联合并,至于主表中没有、从表中有的字段值的记录是不生成在结果中的,反过来,主表中有的、从表中没有的,那么该记录关联的从表的部分的字段值填充为null。

分类:

左外连接

右外连接

接下来就为大家展示通过外连接的方式解决上述内连接所没有解决的问题:

先上SQL(左外连接):

-- 其中dp和ep只是我给部门表和员工表气的别名(相当于小名)
select * from dept dp left join emp ep on dp.deptno=ep.deptno;  
           

执行结果如下:

MySQL DQL操作之高级查询(多表查询篇)

结果分析:

很显然,结果中增加了一条记录,即没有员工的部门,可能你会说,现在不是把部门放到了前面吗?这个无所谓,我换下你就可以了。

上SQL:

-- 因为要制定输出顺序的话,需要使用ep.*,dp.*,但是这种表示因为列名(deptno)一样
# 是会报错的,所以这样写的,不影响结果输出
select ep.*,dp.deptno deptno2,dp.dname,dp.loc from 
dept dp left join emp ep on dp.deptno=ep.deptno; 
           

执行结果如下:

MySQL DQL操作之高级查询(多表查询篇)

就这样需求满足了,其实这种左外连接的方式可以改写成对应的右外连接连接的形式,因为两者可以相互转换。左外连接转右外连接只需要将left改成right,然后把主表和从表交换位置即可,结果是一样的。

上SQL:

select ep.*,dp.deptno deptno2,dp.dname,dp.loc from emp ep right join dept
 dp on dp.deptno=ep.deptno;
           

**注:**执行结果和上面一致,这里就不截图了。

练习:

3) 自然连接

需要注意的是这里的自然连接并不是新的连接方式,而是内连接的一种(等值连接),但是它拥有自己的关键字,因此特此分开。但是因为是等值连接,还有球名称一致,限制比较大,所以应用场景基本为零。
-- 类似内连接的using形式,名称一致的字段进行等值连接
select * from emp natural join dept;
           

练习:leet-code(中文版)[175. 组合两个表]

https://leetcode-cn.com/problems/combine-two-tables/submissions/

继续阅读