MySQL 的 Full Join 的实现

时间:2022-07-22
本文章向大家介绍MySQL 的 Full Join 的实现,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

截止当前最新版本 8.0.19,MySQL 尚未支持 Full Join(全外连接),但我们可以使用其它方式实现 Full Join 的效果。

理论上,全外连接是左外连接和右外连接的组合。完整的外部连接包括联接表中的所有行,无论另一个表是否具有匹配的行。

如果联接表中的行不匹配,则全外连接的结果集将为缺少匹配行的表的每一列设置为 NULL 。对于匹配的行,返回它们关联的结果。

我们来看在其它支持 Full Join 语法的关系数据库的执行情况,有示例表 empdept (这两个表的表结构及数据放在文末)。经过观察,我们可知 emp 表的 7259 编号的员工缺少部门编号,dept 表中编号为 40 的部门在 emp 表中没有对应记录。

图 1 emp 表

图 2 dept 表

执行下面的 SQL 脚本,输出图 3 的结果。

SELECT   * FROM  emp e FULL   JOIN dept d     ON d.deptno = e.deptno

注意,这段 SQL 放到 MySQL 里是无法执行。

图 3 全连接的输出结果

在 MySQL 里,我们通过以下两种方式实现 Full Join 的效果。当然了,还有其它方式也可以实现这效果,就不一一列举了。

方式一:两个 Join 和一个 Union

SELECT   * FROM  emp e   LEFT JOIN dept d     ON d.deptno = e.deptno UNIONSELECT   * FROM  emp e   RIGHT JOIN dept d     ON d.deptno = e.deptno

在这种情况下,这可以提供理想的结果,但并非在所有情况下都正确。

如果 emp 表或者 dept 表存在重复记录,使用这种方式将会移除重复记录。下面我们将通过 UNION ALL 改写这段 SQL,使之完全达到 FULL JOIN 的效果。

方式二:UNION ALL 和排除联接

SELECT   * FROM  emp e   LEFT JOIN dept d     ON d.deptno = e.deptno UNION ALL SELECT   * FROM  emp e   RIGHT JOIN dept d     ON d.deptno = e.deptno WHERE e.deptno IS NULL

这样可以保留同一个表中重复的行,并且保证两个子查询不会产生重复记录。

由于不需要排序和删除重复项,因此对于大型结果集,这可能会大大提高效率。

结语

在工作中,我们用到 full join 的场景可能比较少。那么在什么时候你会想到使用 full join呢?

附上文中用到的表的数据脚本

DROP TABLE IF EXISTS emp;
CREATE TABLE emp (  empno INT NOT NULL,  ename VARCHAR(10) DEFAULT NULL,  job VARCHAR(9) DEFAULT NULL,  mgr INT DEFAULT NULL,  hiredate DATE DEFAULT NULL,  sal DECIMAL(7,2) DEFAULT NULL,  comm DECIMAL(7,2) DEFAULT NULL,  deptno INT DEFAULT NULL);
DROP TABLE IF EXISTS dept;
CREATE TABLE dept (  deptno INT DEFAULT NULL,  dname VARCHAR(14) DEFAULT NULL,  loc VARCHAR(13) DEFAULT NULL);
INSERT INTO emp VALUES (7369,'SMITH','CLERK',7902,'1980-12-17','800.00',NULL,20);INSERT INTO emp VALUES (7499,'ALLEN','SALESMAN',7698,'1981-02-20','1600.00','300.00',30);INSERT INTO emp VALUES (7521,'WARD','SALESMAN',7698,'1981-02-22','1250.00','500.00',30);INSERT INTO emp VALUES (7566,'JONES','MANAGER',7839,'1981-04-02','2975.00',NULL,20);INSERT INTO emp VALUES (7654,'MARTIN','SALESMAN',7698,'1981-09-28','1250.00','1400.00',30);INSERT INTO emp VALUES (7698,'BLAKE','MANAGER',7839,'1981-05-01','2850.00',NULL,30);INSERT INTO emp VALUES (7782,'CLARK','MANAGER',7839,'1981-06-09','2450.00',NULL,10);INSERT INTO emp VALUES (7788,'SCOTT','ANALYST',7566,'1982-12-09','3000.00',NULL,20);INSERT INTO emp VALUES (7839,'KING','PRESIDENT',NULL,'1981-11-17','5000.00',NULL,10);INSERT INTO emp VALUES (7844,'TURNER','SALESMAN',7698,'1981-09-08','1500.00','0.00',30);INSERT INTO emp VALUES (7876,'ADAMS','CLERK',7788,'1983-01-12','1100.00',NULL,20);INSERT INTO emp VALUES (7900,'JAMES','CLERK',7698,'1981-12-03','950.00',NULL,30);INSERT INTO emp VALUES (7902,'FORD','ANALYST',7566,'1981-12-03','3000.00',NULL,20);INSERT INTO emp VALUES (7934,'MILLER','CLERK',7782,'1982-01-23','1300.00',NULL,10);INSERT INTO emp VALUES (7259,'ZHOUXX','MANAGER',7839,'1980-12-19','4800.00',NULL,NULL);
INSERT INTO dept VALUES (10,'ACCOUNTING','NEW YORK');INSERT INTO dept VALUES (20,'RESEARCH','DALLAS');INSERT INTO dept VALUES (30,'SALES','CHICAGO');INSERT INTO dept VALUES (40,'OPERATIONS','BOSTON');