;当一张表的数据无法满足我们的需求时,就需要进行多表查询,而多表查询分为多种情况,这里我先用图来展示,后面用代码验证。
inner join 内连接,取的就是两张表的交集。
select 字段 from tableA inner join tableB on A.key = B.key
left join 左(外)连接,那就是要左表的全部,A和B的共有加上A的独有。
select 字段 from tableA left join tableB on A.key = B.key。
如果A中有的B没有,那么就会用null来补齐。
right join 右(外)连接,右,那就是要右表的全部,A和B的共有加上B的独有。
select 字段 from tableA right join tableB on A.key = B.key
如果B中有而A中没有,那么就会用 null 来补齐。
full outer join,全外连接,就是查询两张表的独有加共有。
select 条件 from tableA full outer join tableB on A.key = B.key MySQL不支持
MySQL如何实现,请看后面代码分析。
下面再说几种情况。
经过上面分析,可以知道,左连接是AB共有加A独有,B没有则用null补齐。那么如果我现在就想要得到A的独有呢?也就是实现下图:
其实也很简单,因为A独有,那么就是B没有,只需要加上一条 where B.key IS NULL 即可,也就是select 字段 from tableA left join tableB on A.key = B.key where B.key IS NULL。
经过where设置B.key IS NULL,即可过滤掉公共部分,剩下A独有部分。
实现下图效果:
如法炮制,既然是查询B独有,那就是A没有,在右连接时加上一条 where B.key IS NULL 即可,也就是
select 条件 from tableA right join tableB on A.key = B.key where A.key IS NULL 。
经过where设置A.key IS NULL,即可过滤掉公共部分,剩下B独有部分。
实现下图效果:
也就是去掉公共部分,中间镂空,只查询A的独有和B的独有,那么也很简单。SQL如下:
select 条件 from tableA full outer join on A.key = B.key where A.key IS NULL and B.key IS NULL
MySQL不支持full outer join,但是思想不变,后面代码分析如何实现。
创建员工表和部门表,并给上一些测试数据。
测试用表和数据奉上:
CREATE TABLE `tbl_emp` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, `deptId` int(11) DEFAULT NULL, PRIMARY KEY (`id`) , KEY `fk_dept_id`(`deptId`) )ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8; CREATE TABLE `tbl_dept` ( `id` int(11) NOT NULL AUTO_INCREMENT, `deptName` varchar(30) DEFAULT NULL, `locAdd` varchar(40) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8; insert into tbl_dept(deptName,locAdd) values('RD',11); insert into tbl_dept(deptName,locAdd) values('HR',12); insert into tbl_dept(deptName,locAdd) values('MK',13); insert into tbl_dept(deptName,locAdd) values('MIS',14); insert into tbl_dept(deptName,locAdd) values('FD',15); insert into tbl_emp(NAME,deptId) values('z3',1); insert into tbl_emp(NAME,deptId) values('z4',1); insert into tbl_emp(NAME,deptId) values('z5',1); insert into tbl_emp(NAME,deptId) values('w5',2); insert into tbl_emp(NAME,deptId) values('w6',2); insert into tbl_emp(NAME,deptId) values('s7',3); insert into tbl_emp(NAME,deptId) values('s8',4); insert into tbl_emp(NAME,deptId) values('s9',51);
为了方便观看,我也将表结构截图展示出来。
tbl_emp表
由雇员的id、雇员的name、雇员的部门id组成。
这里留意一下 deptId,有一个 51,这个 deptId是 tbl_dept 表中没有的。
tbl_dept表
由部门的id、部门名称、部门位置组成,这里部门位置没啥用,就是凑个字段…
这里留意下 id,有一个是 5 ,这是 tbl_emp 表中没有的。
先试下两个表连接,不给连接条件,会出现什么问题。
可以看到,因为我没有给连接条件,所以tbl_emp中的每一条记录都会去匹配tbl_dept中的记录,所以就会有 5 * 8 ,也就40条记录。
sql中 e 和 d是我给两个表起的别名。
可以看到,A(tbl_emp)表和B(tbl_dept)表的共有部分被查询出来。而他们各自独有的记录并没有查询出来。
可以看到,A(tbl_emp)表和B(tbl_dept)表的共有部分被查询出来,并且A的独有部分也被查询出来。这就是左(外)连接。
可以看到,A(tbl_emp)表和B(tbl_dept)表的共有部分被查询出来,并且B的独有部分也被查询出来。这就是右(外)连接。
使用左连接查询,然后使用where过滤,得到A的独有。
使用→连接查询,然后使用where过滤,得到B的独有。
由于MySQL不支持 full outer join,所以全连接需要使用到一个关键字,叫做 union。union的效果就是合并且去重。
全外连接就是查询A、B表的共有,加上A表的独有和B表的独有。这里先用 左连接 和 右连接 先查出A、B共有和A表独有以及A、B共有和B表独有,但是这样公共部分重复了,此时 union 就登场了,union天生带有去重性质,将两次查询结果的重复部分去掉,就得到了全外连接的结果。
使用左连接和右连接并用where过滤掉公共部分得到各自独有部分,然后再通过union进行合并就可以,这里并没有去重的过程。
这几种连接都是学习以及工作中会用到的最基本的,也是最核心的,必须要牢牢掌握,然后向更高进发。