SQL语言 - 连接查询

概述

连接查询包含以下几种类型:

  • 连接查询
    • 内连接:相当于查询A、B交集部分数据
    • 外连接:
    • 左外连接:查询左表所有数据,以及两张表交集部分数据
    • 右外连接:查询右表所有数据,以及两张表交集部分数据
    • 自连接:当前表与自身的连接查询,自连接必须使用表别名

内连接查询

内连接查询的是两张表交集的部分

隐式内连接: SELECT 字段列表 FROM 表1, 表2 WHERE 条件 ...;

显式内连接: SELECT 字段列表 FROM 表1 [ INNER ] JOIN 表2 ON 连接条件 ...;

显式性能比隐式高

例子:

-- 查询员工姓名,及关联的部门的名称
-- 隐式
select e.name,d.name from emp e , dept d where e.dept_id = d.id;
-- 显式
select e.name, d.name from emp e inner join dept d on e.dept_id = d.id;
1
2
3
4
5
mysql> select e.name, d.name from emp e inner join dept d on e.dept_id = d.id;
+-----------+-----------+
| name      | name      |
+-----------+-----------+
| 张无忌    | 研发部    |
| 杨逍      | 研发部    |
| 韦一笑    | 研发部    |
| 常遇春    | 研发部    |
| 小昭      | 研发部    |
| 赵敏      | 市场部    |
| 鹿杖客    | 市场部    |
| 鹤笔翁    | 市场部    |
| 方东白    | 市场部    |
| 灭绝      | 财务部    |
| 周芷若    | 财务部    |
| 丁敏君    | 财务部    |
| 张三丰    | 销售部    |
| 俞莲舟    | 销售部    |
| 宋远桥    | 销售部    |
| 金庸      | 总经办    |
+-----------+-----------+
16 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

外连接查询

左外连接: 查询左表所有数据,以及两张表交集部分数据 SELECT 字段列表 FROM 表1 LEFT [ OUTER ] JOIN 表2 ON 条件 ...; 相当于查询表1的所有数据,包含表1和表2交集部分数据

右外连接: 查询右表所有数据,以及两张表交集部分数据 SELECT 字段列表 FROM 表1 RIGHT [ OUTER ] JOIN 表2 ON 条件 ...;

例子:

-- 左
select e.*, d.name from emp as e left join dept as d on e.dept_id = d.id;
select d.name, e.* from dept d left join emp e on e.dept_id = d.id;  -- 这条语句与下面的语句效果一样,左右连接可以相互转换
-- 右
select d.name, e.* from emp as e right join dept as d on e.dept_id = d.id;
1
2
3
4
5
mysql> select e.*, d.name from emp as e left join dept as d on e.dept_id = d.id;
+----+-----------+------+--------------------+--------+------------+-----------+---------+-----------+
| id | name      | age  | job                | salary | entrydate  | managerid | dept_id | name      |
+----+-----------+------+--------------------+--------+------------+-----------+---------+-----------+
|  1 | 金庸      |   66 | 总裁               |  20000 | 2000-01-01 |      NULL |       5 | 总经办    |
|  2 | 张无忌    |   20 | 项目经理           |  12500 | 2005-12-05 |         1 |       1 | 研发部    |
|  3 | 杨逍      |   33 | 开发               |   8400 | 2000-11-03 |         2 |       1 | 研发部    |
|  4 | 韦一笑    |   48 | 开发               |  11000 | 2002-02-05 |         2 |       1 | 研发部    |
|  5 | 常遇春    |   43 | 开发               |  10500 | 2004-09-07 |         3 |       1 | 研发部    |
|  6 | 小昭      |   19 | 程序员鼓励师       |   6600 | 2004-10-12 |         2 |       1 | 研发部    |
|  7 | 灭绝      |   60 | 财务总监           |   8500 | 2002-09-12 |         1 |       3 | 财务部    |
|  8 | 周芷若    |   19 | 会计               |  48000 | 2006-06-02 |         7 |       3 | 财务部    |
|  9 | 丁敏君    |   23 | 出纳               |   5250 | 2009-05-13 |         7 |       3 | 财务部    |
| 10 | 赵敏      |   20 | 市场部总监         |  12500 | 2004-10-12 |         1 |       2 | 市场部    |
| 11 | 鹿杖客    |   56 | 职员               |   3750 | 2006-10-03 |        10 |       2 | 市场部    |
| 12 | 鹤笔翁    |   19 | 职员               |   3750 | 2007-05-09 |        10 |       2 | 市场部    |
| 13 | 方东白    |   19 | 职员               |   5500 | 2009-02-12 |        10 |       2 | 市场部    |
| 14 | 张三丰    |   88 | 销售总监           |  14000 | 2004-10-12 |         1 |       4 | 销售部    |
| 15 | 俞莲舟    |   38 | 销售               |   4600 | 2004-10-12 |        14 |       4 | 销售部    |
| 16 | 宋远桥    |   40 | 销售               |   4600 | 2004-10-12 |        14 |       4 | 销售部    |
| 17 | 陈友谅    |   42 | NULL               |   2000 | 2011-10-12 |         1 |    NULL | NULL      |
+----+-----------+------+--------------------+--------+------------+-----------+---------+-----------+
17 rows in set (0.01 sec)

mysql> select d.name, e.* from dept d left join emp e on e.dept_id = d.id;
+-----------+------+-----------+------+--------------------+--------+------------+-----------+---------+
| name      | id   | name      | age  | job                | salary | entrydate  | managerid | dept_id |
+-----------+------+-----------+------+--------------------+--------+------------+-----------+---------+
| 研发部    |    2 | 张无忌    |   20 | 项目经理           |  12500 | 2005-12-05 |         1 |       1 |
| 研发部    |    3 | 杨逍      |   33 | 开发               |   8400 | 2000-11-03 |         2 |       1 |
| 研发部    |    4 | 韦一笑    |   48 | 开发               |  11000 | 2002-02-05 |         2 |       1 |
| 研发部    |    5 | 常遇春    |   43 | 开发               |  10500 | 2004-09-07 |         3 |       1 |
| 研发部    |    6 | 小昭      |   19 | 程序员鼓励师       |   6600 | 2004-10-12 |         2 |       1 |
| 市场部    |   10 | 赵敏      |   20 | 市场部总监         |  12500 | 2004-10-12 |         1 |       2 |
| 市场部    |   11 | 鹿杖客    |   56 | 职员               |   3750 | 2006-10-03 |        10 |       2 |
| 市场部    |   12 | 鹤笔翁    |   19 | 职员               |   3750 | 2007-05-09 |        10 |       2 |
| 市场部    |   13 | 方东白    |   19 | 职员               |   5500 | 2009-02-12 |        10 |       2 |
| 财务部    |    7 | 灭绝      |   60 | 财务总监           |   8500 | 2002-09-12 |         1 |       3 |
| 财务部    |    8 | 周芷若    |   19 | 会计               |  48000 | 2006-06-02 |         7 |       3 |
| 财务部    |    9 | 丁敏君    |   23 | 出纳               |   5250 | 2009-05-13 |         7 |       3 |
| 销售部    |   14 | 张三丰    |   88 | 销售总监           |  14000 | 2004-10-12 |         1 |       4 |
| 销售部    |   15 | 俞莲舟    |   38 | 销售               |   4600 | 2004-10-12 |        14 |       4 |
| 销售部    |   16 | 宋远桥    |   40 | 销售               |   4600 | 2004-10-12 |        14 |       4 |
| 总经办    |    1 | 金庸      |   66 | 总裁               |  20000 | 2000-01-01 |      NULL |       5 |
| 人事部    | NULL | NULL      | NULL | NULL               |   NULL | NULL       |      NULL |    NULL |
+-----------+------+-----------+------+--------------------+--------+------------+-----------+---------+
17 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

左连接可以查询到没有dept的emp,右连接可以查询到没有emp的dept

自连接

自连接查询

自连接查询,顾名思义,就是自己连接自己,也就是把一张表连接查询多次。

语法: SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件 ...;

自连接查询,可以是内连接查询,也可以是外连接查询

例子:

-- 查询员工及其所属领导的名字
select a.name , b.name from emp a , emp b where a.managerid = b.id;
-- 没有领导的也查询出来
select a.name '员工', b.name '领导' from emp a left join emp b on a.managerid =b.id;
1
2
3
4
mysql> select a.name , b.name from emp a , emp b where a.managerid = b.id;
+-----------+-----------+
| name      | name      |
+-----------+-----------+
| 张无忌    | 金庸      |
| 杨逍      | 张无忌    |
| 韦一笑    | 张无忌    |
| 常遇春    | 杨逍      |
| 小昭      | 张无忌    |
| 灭绝      | 金庸      |
| 周芷若    | 灭绝      |
| 丁敏君    | 灭绝      |
| 赵敏      | 金庸      |
| 鹿杖客    | 赵敏      |
| 鹤笔翁    | 赵敏      |
| 方东白    | 赵敏      |
| 张三丰    | 金庸      |
| 俞莲舟    | 张三丰    |
| 宋远桥    | 张三丰    |
| 陈友谅    | 金庸      |
+-----------+-----------+
16 rows in set (0.00 sec)

mysql> select a.name '员工', b.name '领导' from emp a left join emp b on a.managerid =b.id;
+-----------+-----------+
| 员工      | 领导      |
+-----------+-----------+
| 金庸      | NULL      |
| 张无忌    | 金庸      |
| 杨逍      | 张无忌    |
| 韦一笑    | 张无忌    |
| 常遇春    | 杨逍      |
| 小昭      | 张无忌    |
| 灭绝      | 金庸      |
| 周芷若    | 灭绝      |
| 丁敏君    | 灭绝      |
| 赵敏      | 金庸      |
| 鹿杖客    | 赵敏      |
| 鹤笔翁    | 赵敏      |
| 方东白    | 赵敏      |
| 张三丰    | 金庸      |
| 俞莲舟    | 张三丰    |
| 宋远桥    | 张三丰    |
| 陈友谅    | 金庸      |
+-----------+-----------+
17 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

联合查询 union, union all

对于union查询,就是把多次查询的结果合并起来,形成一个新的查询结果集。

语法:

SELECT 字段列表 FROM 表A ...
UNION [ALL]
SELECT 字段列表 FROM 表B ...
1
2
3
  • 对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致。
  • union all 会将全部的数据直接合并在一起,union 会对合并之后的数据去重。
  • 联合查询比使用or效率高,不会使索引失效
-- 将薪资低于 5000 的员工 , 和 年龄大于 50 岁的员工全部查询出来.
select * from emp where salary < 5000
union all
select * from emp where age > 50;
-- union all查询出来的结果,仅仅进行简单的合并,并未去重。
select * from emp where salary < 5000
union
select * from emp where age > 50;
-- 等价于
select * from emp where salary < 5000 or age > 50;
1
2
3
4
5
6
7
8
9
10
mysql> select * from emp where salary < 5000 union select * from emp where age > 50;
+----+-----------+------+--------------+--------+------------+-----------+---------+
| id | name      | age  | job          | salary | entrydate  | managerid | dept_id |
+----+-----------+------+--------------+--------+------------+-----------+---------+
| 11 | 鹿杖客    |   56 | 职员         |   3750 | 2006-10-03 |        10 |       2 |
| 12 | 鹤笔翁    |   19 | 职员         |   3750 | 2007-05-09 |        10 |       2 |
| 15 | 俞莲舟    |   38 | 销售         |   4600 | 2004-10-12 |        14 |       4 |
| 16 | 宋远桥    |   40 | 销售         |   4600 | 2004-10-12 |        14 |       4 |
| 17 | 陈友谅    |   42 | NULL         |   2000 | 2011-10-12 |         1 |    NULL |
|  1 | 金庸      |   66 | 总裁         |  20000 | 2000-01-01 |      NULL |       5 |
|  7 | 灭绝      |   60 | 财务总监     |   8500 | 2002-09-12 |         1 |       3 |
| 14 | 张三丰    |   88 | 销售总监     |  14000 | 2004-10-12 |         1 |       4 |
+----+-----------+------+--------------+--------+------------+-----------+---------+
8 rows in set (0.00 sec)

mysql> select * from emp where salary < 5000 or age > 50;
+----+-----------+------+--------------+--------+------------+-----------+---------+
| id | name      | age  | job          | salary | entrydate  | managerid | dept_id |
+----+-----------+------+--------------+--------+------------+-----------+---------+
|  1 | 金庸      |   66 | 总裁         |  20000 | 2000-01-01 |      NULL |       5 |
|  7 | 灭绝      |   60 | 财务总监     |   8500 | 2002-09-12 |         1 |       3 |
| 11 | 鹿杖客    |   56 | 职员         |   3750 | 2006-10-03 |        10 |       2 |
| 12 | 鹤笔翁    |   19 | 职员         |   3750 | 2007-05-09 |        10 |       2 |
| 14 | 张三丰    |   88 | 销售总监     |  14000 | 2004-10-12 |         1 |       4 |
| 15 | 俞莲舟    |   38 | 销售         |   4600 | 2004-10-12 |        14 |       4 |
| 16 | 宋远桥    |   40 | 销售         |   4600 | 2004-10-12 |        14 |       4 |
| 17 | 陈友谅    |   42 | NULL         |   2000 | 2011-10-12 |         1 |    NULL |
+----+-----------+------+--------------+--------+------------+-----------+---------+
8 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29