目录
表的内连和外连
表的连接分为内连接和外连接
内连接
内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选,我们前面学习的查询都是内连接,也是在开发过程中使用的最多的连接查询。
通俗解释 :内连接就像一次"严格匹配"的相亲大会。只把双方都符合条件(有共同department_id) 的信息配对成功并展示出来 。如果有人没有对象 (比如赵六的department_id是NULL),或者有对象但对方没来 (比如市场部在员工表里没人),那他们就不会出现在结果里。
语法:
select 字段 from 表1 inner join 表2 on 连接条件 and 其他条件;
inner join
可以简写成 join
,因为MySQL
默认就是内连接。
备注:前面学习的都是内连接
案例:显示SMITH的名字和部门名称
c
-- 用前面的写法
mysql> select ename,dname from emp,dept where emp.deptno = dept.deptno and ename = 'SMITH';
+-------+----------+
| ename | dname |
+-------+----------+
| SMITH | RESEARCH |
+-------+----------+
1 row in set (0.00 sec)
-- 用标准的内连接写法
mysql> select ename,dname from emp inner join dept on emp.deptno=dept.deptno and ename='SMITH';
+-------+----------+
| ename | dname |
+-------+----------+
| SMITH | RESEARCH |
+-------+----------+
1 row in set (0.00 sec)
使用场景:当你只想获取在两个表中都有对应关系的数据时,就用内连接。
- 查询订单和客户信息(只查看已下单的客户)。
- 查询学生和选课信息(只查看有学生选的课程)。
- 查询文章和评论(只查看有评论的文章)。
外连接
外连接分为左外连接、右外连接和全外连接。MySQL不支持全外连接,所以我们重点讲前两个。
左外连接
如果联合查询,左侧的表完全显示我们就说是左外连接。
左外连接 - "以左表为绝对核心"
通俗解释:左连接就像公司的人力资源部做全员统计。左边的员工表是核心,一个都不能少。不管员工有没有部门(department_id是否为空),都要出现在名单上。然后,再去右边的部门表里找匹配的部门名称,如果找不到,就用NULL填充。
语法:
select 字段名 from 表名1 left join 表名2 on 连接条件
案例:
c
--- 创建两张表
mysql> create table stu( id int, name varchar(30));
Query OK, 0 rows affected (0.02 sec)
mysql> create table exam(
-> id int,
-> grade int);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into stu values (1,'Jon'),(2,'Tom'),(4,'Lisa'),(5,'Lili');
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> insert into exam values(1,12),(2,34),(11,9);
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from stu;
+------+------+
| id | name |
+------+------+
| 1 | Jon |
| 2 | Tom |
| 4 | Lisa |
| 5 | Lili |
+------+------+
4 rows in set (0.00 sec)
mysql> select * from exam;
+------+-------+
| id | grade |
+------+-------+
| 1 | 12 |
| 2 | 34 |
| 11 | 9 |
+------+-------+
3 rows in set (0.00 sec)
- 查询所有学生的成绩,如果这个学生没有成绩,也要将学生的个人信息显示出来
c
-- 左外连接:当左边表和右边表没有匹配时,也会显示左边表的数据
mysql> select * from stu left join exam on stu.id=exam.id;
+------+------+------+-------+
| id | name | id | grade |
+------+------+------+-------+
| 1 | Jon | 1 | 12 |
| 2 | Tom | 2 | 34 |
| 4 | Lisa | NULL | NULL |
| 5 | Lili | NULL | NULL |
+------+------+------+-------+
4 rows in set (0.00 sec)
--- 内连接:只显示匹配数据
mysql> select * from stu inner join exam on stu.id=exam.id;
+------+------+------+-------+
| id | name | id | grade |
+------+------+------+-------+
| 1 | Jon | 1 | 12 |
| 2 | Tom | 2 | 34 |
+------+------+------+-------+
2 rows in set (0.00 sec)
使用场景:当你需要获取左表的全部记录,以及右表中与之匹配的记录时。
- 统计每个客户的订单量(包括没下过单的客户)。
- 查找所有员工的信息,包括尚未分配部门的员工(如上例)。
- 计算每个产品的销售总额,包括一件都没卖出去的产品。
右外连接
如果联合查询,右侧的表完全显示我们就说是右外连接。
右外连接 - "以右表为绝对核心"
通俗解释:右连接和左连接完全相反。它以右边的表为核心,一个都不能少。然后去左边的表里找匹配项,找不到就用NULL填充。在实际开发中,右连接用得较少,因为我们可以通过调整表的顺序,用左连接来实现同样的效果,这样代码更统一,更易读。
语法:
select 字段 from 表名1 right join 表名2 on 连接条件;
案例:
- 对stu表和exam表联合查询,把所有的成绩都显示出来,即使这个成绩没有学生与它对应,也要显示出来
c
mysql> select * from stu right join exam on stu.id=exam.id;
+------+------+------+-------+
| id | name | id | grade |
+------+------+------+-------+
| 1 | Jon | 1 | 12 |
| 2 | Tom | 2 | 34 |
| NULL | NULL | 11 | 9 |
+------+------+------+-------+
3 rows in set (0.00 sec)
练习:
- 列出部门名称和这些部门的员工信息,同时列出没有员工的部门
c
--- 方法1:使用左外连接
mysql> select dept.deptno,dept.dname,empno,ename,job from dept left join emp on dept.deptno=emp.deptno;
+--------+------------+--------+--------+-----------+
| deptno | dname | empno | ename | job |
+--------+------------+--------+--------+-----------+
| 10 | ACCOUNTING | 007934 | MILLER | CLERK |
| 10 | ACCOUNTING | 007839 | KING | PRESIDENT |
| 10 | ACCOUNTING | 007782 | CLARK | MANAGER |
| 20 | RESEARCH | 007902 | FORD | ANALYST |
| 20 | RESEARCH | 007876 | ADAMS | CLERK |
| 20 | RESEARCH | 007788 | SCOTT | ANALYST |
| 20 | RESEARCH | 007566 | JONES | MANAGER |
| 20 | RESEARCH | 007369 | SMITH | CLERK |
| 30 | SALES | 007900 | JAMES | CLERK |
| 30 | SALES | 007844 | TURNER | SALESMAN |
| 30 | SALES | 007698 | BLAKE | MANAGER |
| 30 | SALES | 007654 | MARTIN | SALESMAN |
| 30 | SALES | 007521 | WARD | SALESMAN |
| 30 | SALES | 007499 | ALLEN | SALESMAN |
| 40 | OPERATIONS | NULL | NULL | NULL |
+--------+------------+--------+--------+-----------+
15 rows in set (0.00 sec)
这个查询和上面的右连接查询结果完全一样。所以,掌握左连接就足够了。
c
--- 方法2:使用右外连接
mysql> select dept.deptno,dept.dname,empno,ename,job from emp right join dept on dept.deptno=emp.deptno;
+--------+------------+--------+--------+-----------+
| deptno | dname | empno | ename | job |
+--------+------------+--------+--------+-----------+
| 10 | ACCOUNTING | 007934 | MILLER | CLERK |
| 10 | ACCOUNTING | 007839 | KING | PRESIDENT |
| 10 | ACCOUNTING | 007782 | CLARK | MANAGER |
| 20 | RESEARCH | 007902 | FORD | ANALYST |
| 20 | RESEARCH | 007876 | ADAMS | CLERK |
| 20 | RESEARCH | 007788 | SCOTT | ANALYST |
| 20 | RESEARCH | 007566 | JONES | MANAGER |
| 20 | RESEARCH | 007369 | SMITH | CLERK |
| 30 | SALES | 007900 | JAMES | CLERK |
| 30 | SALES | 007844 | TURNER | SALESMAN |
| 30 | SALES | 007698 | BLAKE | MANAGER |
| 30 | SALES | 007654 | MARTIN | SALESMAN |
| 30 | SALES | 007521 | WARD | SALESMAN |
| 30 | SALES | 007499 | ALLEN | SALESMAN |
| 40 | OPERATIONS | NULL | NULL | NULL |
+--------+------------+--------+--------+-----------+
15 rows in set (0.00 sec)
--- 可以使用别名
mysql> select d.deptno,d.dname,e.empno,e.ename,e.job from emp e right join dept d on d.deptno=e.deptno;

一句话记忆:
内连接:求交集,严格匹配。
左连接:保左全,右填空。
右连接:保右全,左填空(但通常用"调换表顺序的左连接"来代替)。