1. 定义

  • 多表查询,也称为关联查询,指两个或更多个表一起完成查询操作
  • 前提条件:这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段,这个关联字段可能建立了外键,也可能没有建立外键。比如:员工表和部门表,这两个表依靠“部门编号”进行关联

1.1 笛卡尔积的错误

SELECT last_name, department_name FROM employees, departments;
  • employees表中有107条数据
  • departments表中有27条数据
  • 上述的查询语句,查出来了2889条数据,而2889 = 107 * 27;这种查询出来的错误,称为:笛卡尔积的错误。

1.2 笛卡尔积(或交叉连接)的理解

  • 笛卡尔乘积是一个数学运算。假设我有两个集合 X 和 Y,那么 X 和 Y 的笛卡尔积就是 X 和 Y 的所有可能组合,也就是第一个对象来自于 X,第二个对象来自于 Y 的所有可能。组合的个数即为两个集合中元素个数的乘积数
  • 笛卡尔积的错误会在下面条件下产生:
    • 省略多个表的连接条件(或关联条件)
    • 连接条件(或关联条件)无效
    • 所有表中的所有行互相连接
  • 为了避免笛卡尔积, 可以在 WHERE 加入有效的连接条件
SELECT last_name, department_name FROM employees, departments 
WHERE employees.department_id = departments.department_id;  #连接条件
  • 在 WHERE子句中写入连接条件
  • 在表中有相同列时,在列名之前加上表名前缀

2. 多表查询分类

2.1 等值连接 vs 非等值连接

  • 等值连接
mysql> SELECT last_name, department_name FROM employees, departments 
    -> WHERE employees.department_id = departments.department_id; 
+-------------+------------------+
| last_name   | department_name  |
+-------------+------------------+
| Whalen      | Administration   |
| Hartstein   | Marketing        |
| Fay         | Marketing        |
| Raphaely    | Purchasing       |
| Khoo        | Purchasing       |
| Baida       | Purchasing       |
| Tobias      | Purchasing       |
| Himuro      | Purchasing       |
| Colmenares  | Purchasing       |
| Mavris      | Human Resources  |
| Weiss       | Shipping         |
| Fripp       | Shipping         |
| Kaufling    | Shipping         |
| Vollman     | Shipping         |
| Mourgos     | Shipping         |
| Nayer       | Shipping         |
| Mikkilineni | Shipping         |
| Landry      | Shipping         |
| Markle      | Shipping         |
| Bissot      | Shipping         |
| Atkinson    | Shipping         |
| Marlow      | Shipping         |
| Olson       | Shipping         |
| Mallin      | Shipping         |
| Rogers      | Shipping         |
| Gee         | Shipping         |
| Philtanker  | Shipping         |
| Ladwig      | Shipping         |
| Stiles      | Shipping         |
| Seo         | Shipping         |
| Patel       | Shipping         |
| Rajs        | Shipping         |
| Davies      | Shipping         |
| Matos       | Shipping         |
| Vargas      | Shipping         |
| Taylor      | Shipping         |
| Fleaur      | Shipping         |
| Sullivan    | Shipping         |
| Geoni       | Shipping         |
| Sarchand    | Shipping         |
| Bull        | Shipping         |
| Dellinger   | Shipping         |
| Cabrio      | Shipping         |
| Chung       | Shipping         |
| Dilly       | Shipping         |
| Gates       | Shipping         |
| Perkins     | Shipping         |
| Bell        | Shipping         |
| Everett     | Shipping         |
| McCain      | Shipping         |
| Jones       | Shipping         |
| Walsh       | Shipping         |
| Feeney      | Shipping         |
| OConnell    | Shipping         |
| Grant       | Shipping         |
| Hunold      | IT               |
| Ernst       | IT               |
| Austin      | IT               |
| Pataballa   | IT               |
| Lorentz     | IT               |
| Baer        | Public Relations |
| Russell     | Sales            |
| Partners    | Sales            |
| Errazuriz   | Sales            |
| Cambrault   | Sales            |
| Zlotkey     | Sales            |
| Tucker      | Sales            |
| Bernstein   | Sales            |
| Hall        | Sales            |
| Olsen       | Sales            |
| Cambrault   | Sales            |
| Tuvault     | Sales            |
| King        | Sales            |
| Sully       | Sales            |
| McEwen      | Sales            |
| Smith       | Sales            |
| Doran       | Sales            |
| Sewall      | Sales            |
| Vishney     | Sales            |
| Greene      | Sales            |
| Marvins     | Sales            |
| Lee         | Sales            |
| Ande        | Sales            |
| Banda       | Sales            |
| Ozer        | Sales            |
| Bloom       | Sales            |
| Fox         | Sales            |
| Smith       | Sales            |
| Bates       | Sales            |
| Kumar       | Sales            |
| Abel        | Sales            |
| Hutton      | Sales            |
| Taylor      | Sales            |
| Livingston  | Sales            |
| Johnson     | Sales            |
| King        | Executive        |
| Kochhar     | Executive        |
| De Haan     | Executive        |
| Greenberg   | Finance          |
| Faviet      | Finance          |
| Chen        | Finance          |
| Sciarra     | Finance          |
| Urman       | Finance          |
| Popp        | Finance          |
| Higgins     | Accounting       |
| Gietz       | Accounting       |
+-------------+------------------+
106 rows in set (0.01 sec)

mysql>
  • 非等值连接
mysql> SELECT last_name, salary, grade_level
    -> FROM employees e,job_grades j
    -> WHERE e.salary BETWEEN j.lowest_sal AND j.highest_sal;
+-------------+----------+-------------+
| last_name   | salary   | grade_level |
+-------------+----------+-------------+
| King        | 24000.00 | E           |
| Kochhar     | 17000.00 | E           |
| De Haan     | 17000.00 | E           |
| Hunold      |  9000.00 | C           |
| Ernst       |  6000.00 | C           |
| Austin      |  4800.00 | B           |
| Pataballa   |  4800.00 | B           |
| Lorentz     |  4200.00 | B           |
| Greenberg   | 12000.00 | D           |
| Faviet      |  9000.00 | C           |
| Chen        |  8200.00 | C           |
| Sciarra     |  7700.00 | C           |
| Urman       |  7800.00 | C           |
| Popp        |  6900.00 | C           |
| Raphaely    | 11000.00 | D           |
| Khoo        |  3100.00 | B           |
| Baida       |  2900.00 | A           |
| Tobias      |  2800.00 | A           |
| Himuro      |  2600.00 | A           |
| Colmenares  |  2500.00 | A           |
| Weiss       |  8000.00 | C           |
| Fripp       |  8200.00 | C           |
| Kaufling    |  7900.00 | C           |
| Vollman     |  6500.00 | C           |
| Mourgos     |  5800.00 | B           |
| Nayer       |  3200.00 | B           |
| Mikkilineni |  2700.00 | A           |
| Landry      |  2400.00 | A           |
| Markle      |  2200.00 | A           |
| Bissot      |  3300.00 | B           |
| Atkinson    |  2800.00 | A           |
| Marlow      |  2500.00 | A           |
| Olson       |  2100.00 | A           |
| Mallin      |  3300.00 | B           |
| Rogers      |  2900.00 | A           |
| Gee         |  2400.00 | A           |
| Philtanker  |  2200.00 | A           |
| Ladwig      |  3600.00 | B           |
| Stiles      |  3200.00 | B           |
| Seo         |  2700.00 | A           |
| Patel       |  2500.00 | A           |
| Rajs        |  3500.00 | B           |
| Davies      |  3100.00 | B           |
| Matos       |  2600.00 | A           |
| Vargas      |  2500.00 | A           |
| Russell     | 14000.00 | D           |
| Partners    | 13500.00 | D           |
| Errazuriz   | 12000.00 | D           |
| Cambrault   | 11000.00 | D           |
| Zlotkey     | 10500.00 | D           |
| Tucker      | 10000.00 | D           |
| Bernstein   |  9500.00 | C           |
| Hall        |  9000.00 | C           |
| Olsen       |  8000.00 | C           |
| Cambrault   |  7500.00 | C           |
| Tuvault     |  7000.00 | C           |
| King        | 10000.00 | D           |
| Sully       |  9500.00 | C           |
| McEwen      |  9000.00 | C           |
| Smith       |  8000.00 | C           |
| Doran       |  7500.00 | C           |
| Sewall      |  7000.00 | C           |
| Vishney     | 10500.00 | D           |
| Greene      |  9500.00 | C           |
| Marvins     |  7200.00 | C           |
| Lee         |  6800.00 | C           |
| Ande        |  6400.00 | C           |
| Banda       |  6200.00 | C           |
| Ozer        | 11500.00 | D           |
| Bloom       | 10000.00 | D           |
| Fox         |  9600.00 | C           |
| Smith       |  7400.00 | C           |
| Bates       |  7300.00 | C           |
| Kumar       |  6100.00 | C           |
| Abel        | 11000.00 | D           |
| Hutton      |  8800.00 | C           |
| Taylor      |  8600.00 | C           |
| Livingston  |  8400.00 | C           |
| Grant       |  7000.00 | C           |
| Johnson     |  6200.00 | C           |
| Taylor      |  3200.00 | B           |
| Fleaur      |  3100.00 | B           |
| Sullivan    |  2500.00 | A           |
| Geoni       |  2800.00 | A           |
| Sarchand    |  4200.00 | B           |
| Bull        |  4100.00 | B           |
| Dellinger   |  3400.00 | B           |
| Cabrio      |  3000.00 | B           |
| Chung       |  3800.00 | B           |
| Dilly       |  3600.00 | B           |
| Gates       |  2900.00 | A           |
| Perkins     |  2500.00 | A           |
| Bell        |  4000.00 | B           |
| Everett     |  3900.00 | B           |
| McCain      |  3200.00 | B           |
| Jones       |  2800.00 | A           |
| Walsh       |  3100.00 | B           |
| Feeney      |  3000.00 | B           |
| OConnell    |  2600.00 | A           |
| Grant       |  2600.00 | A           |
| Whalen      |  4400.00 | B           |
| Hartstein   | 13000.00 | D           |
| Fay         |  6000.00 | C           |
| Mavris      |  6500.00 | C           |
| Baer        | 10000.00 | D           |
| Higgins     | 12000.00 | D           |
| Gietz       |  8300.00 | C           |
+-------------+----------+-------------+
107 rows in set (0.00 sec)

mysql> 

2.2 自连接 vs 非自连接

  • 自连接
  • employees表中的employee_id和manager_id 有关联
    • employees中 emp作为员工,mgr作为管理者
mysql> SELECT emp.employee_id,emp.last_name, mgr.employee_id,mgr.last_name
    -> FROM employees emp, employees mgr
    -> WHERE emp.manager_id = mgr.employee_id;
+-------------+-------------+-------------+-----------+
| employee_id | last_name   | employee_id | last_name |
+-------------+-------------+-------------+-----------+
|         101 | Kochhar     |         100 | King      |
|         102 | De Haan     |         100 | King      |
|         103 | Hunold      |         102 | De Haan   |
|         104 | Ernst       |         103 | Hunold    |
|         105 | Austin      |         103 | Hunold    |
|         106 | Pataballa   |         103 | Hunold    |
|         107 | Lorentz     |         103 | Hunold    |
|         108 | Greenberg   |         101 | Kochhar   |
|         109 | Faviet      |         108 | Greenberg |
|         110 | Chen        |         108 | Greenberg |
|         111 | Sciarra     |         108 | Greenberg |
|         112 | Urman       |         108 | Greenberg |
|         113 | Popp        |         108 | Greenberg |
|         114 | Raphaely    |         100 | King      |
|         115 | Khoo        |         114 | Raphaely  |
|         116 | Baida       |         114 | Raphaely  |
|         117 | Tobias      |         114 | Raphaely  |
|         118 | Himuro      |         114 | Raphaely  |
|         119 | Colmenares  |         114 | Raphaely  |
|         120 | Weiss       |         100 | King      |
|         121 | Fripp       |         100 | King      |
|         122 | Kaufling    |         100 | King      |
|         123 | Vollman     |         100 | King      |
|         124 | Mourgos     |         100 | King      |
|         125 | Nayer       |         120 | Weiss     |
|         126 | Mikkilineni |         120 | Weiss     |
|         127 | Landry      |         120 | Weiss     |
|         128 | Markle      |         120 | Weiss     |
|         129 | Bissot      |         121 | Fripp     |
|         130 | Atkinson    |         121 | Fripp     |
|         131 | Marlow      |         121 | Fripp     |
|         132 | Olson       |         121 | Fripp     |
|         133 | Mallin      |         122 | Kaufling  |
|         134 | Rogers      |         122 | Kaufling  |
|         135 | Gee         |         122 | Kaufling  |
|         136 | Philtanker  |         122 | Kaufling  |
|         137 | Ladwig      |         123 | Vollman   |
|         138 | Stiles      |         123 | Vollman   |
|         139 | Seo         |         123 | Vollman   |
|         140 | Patel       |         123 | Vollman   |
|         141 | Rajs        |         124 | Mourgos   |
|         142 | Davies      |         124 | Mourgos   |
|         143 | Matos       |         124 | Mourgos   |
|         144 | Vargas      |         124 | Mourgos   |
|         145 | Russell     |         100 | King      |
|         146 | Partners    |         100 | King      |
|         147 | Errazuriz   |         100 | King      |
|         148 | Cambrault   |         100 | King      |
|         149 | Zlotkey     |         100 | King      |
|         150 | Tucker      |         145 | Russell   |
|         151 | Bernstein   |         145 | Russell   |
|         152 | Hall        |         145 | Russell   |
|         153 | Olsen       |         145 | Russell   |
|         154 | Cambrault   |         145 | Russell   |
|         155 | Tuvault     |         145 | Russell   |
|         156 | King        |         146 | Partners  |
|         157 | Sully       |         146 | Partners  |
|         158 | McEwen      |         146 | Partners  |
|         159 | Smith       |         146 | Partners  |
|         160 | Doran       |         146 | Partners  |
|         161 | Sewall      |         146 | Partners  |
|         162 | Vishney     |         147 | Errazuriz |
|         163 | Greene      |         147 | Errazuriz |
|         164 | Marvins     |         147 | Errazuriz |
|         165 | Lee         |         147 | Errazuriz |
|         166 | Ande        |         147 | Errazuriz |
|         167 | Banda       |         147 | Errazuriz |
|         168 | Ozer        |         148 | Cambrault |
|         169 | Bloom       |         148 | Cambrault |
|         170 | Fox         |         148 | Cambrault |
|         171 | Smith       |         148 | Cambrault |
|         172 | Bates       |         148 | Cambrault |
|         173 | Kumar       |         148 | Cambrault |
|         174 | Abel        |         149 | Zlotkey   |
|         175 | Hutton      |         149 | Zlotkey   |
|         176 | Taylor      |         149 | Zlotkey   |
|         177 | Livingston  |         149 | Zlotkey   |
|         178 | Grant       |         149 | Zlotkey   |
|         179 | Johnson     |         149 | Zlotkey   |
|         180 | Taylor      |         120 | Weiss     |
|         181 | Fleaur      |         120 | Weiss     |
|         182 | Sullivan    |         120 | Weiss     |
|         183 | Geoni       |         120 | Weiss     |
|         184 | Sarchand    |         121 | Fripp     |
|         185 | Bull        |         121 | Fripp     |
|         186 | Dellinger   |         121 | Fripp     |
|         187 | Cabrio      |         121 | Fripp     |
|         188 | Chung       |         122 | Kaufling  |
|         189 | Dilly       |         122 | Kaufling  |
|         190 | Gates       |         122 | Kaufling  |
|         191 | Perkins     |         122 | Kaufling  |
|         192 | Bell        |         123 | Vollman   |
|         193 | Everett     |         123 | Vollman   |
|         194 | McCain      |         123 | Vollman   |
|         195 | Jones       |         123 | Vollman   |
|         196 | Walsh       |         124 | Mourgos   |
|         197 | Feeney      |         124 | Mourgos   |
|         198 | OConnell    |         124 | Mourgos   |
|         199 | Grant       |         124 | Mourgos   |
|         200 | Whalen      |         101 | Kochhar   |
|         201 | Hartstein   |         100 | King      |
|         202 | Fay         |         201 | Hartstein |
|         203 | Mavris      |         101 | Kochhar   |
|         204 | Baer        |         101 | Kochhar   |
|         205 | Higgins     |         101 | Kochhar   |
|         206 | Gietz       |         205 | Higgins   |
+-------------+-------------+-------------+-----------+
106 rows in set (0.00 sec)

mysql> 

2.3 内连接 vs 外连接

  • 内连接
    • 合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行
    • 上面的两大类的分类的连接全部属于内连接
SELECT employee_id,department_name
FROM employees e,departments d
WHERE e.`department_id` = d.department_id;  #只有106条记录
  • 外连接
    • 两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)
    • 如果是左外连接,则连接条件中左边的表也称为 主表 ,右边的表称为 从表
    • 如果是右外连接,则连接条件中右边的表也称为 主表 ,左边的表称为 从表
  • 外连接的分类:左外连接、右外连接、满外连接
    • 左外连接:两个表在连接过程中除了返回满足连接条件的行以外还返回左表中不满足条件的行,这种连接称为左外连接。
    • 右外连接:两个表在连接过程中除了返回满足连接条件的行以外还返回右表中不满足条件的行,这种连接称为右外连接。
# SQL92语法实现内连接:见上,略
# SQL92语法实现外连接:使用 +  ----------MySQL不支持SQL92语法中外连接的写法!
mysql> SELECT employee_id,department_name
    -> FROM employees e,departments d
    -> WHERE e.`department_id` = d.department_id(+);  #左外连接
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 3
mysql> 

#右外连接
SELECT employee_id,department_name
FROM employees e,departments d
WHERE e.`department_id`(+) = d.department_id; 

3. SQL99语法实现多表查询

  • 使用JOIN...ON子句创建连接的语法结构
    • 可以使用 ON 子句指定额外的连接条件

3.1 内连接(INNER JOIN)的实现

  • 语法:
# 其中 INNER 可以省略
SELECT 字段列表 FROM A表 INNER JOIN B表 ON 关联条件 WHERE 等其他子句;
  • 例子:
SELECT last_name,department_name
FROM employees e INNER JOIN departments d
ON e.department_id = d.department_id;

SELECT last_name, department_name, city
FROM employees e JOIN departments d
ON e.department_id = d.department_id
JOIN locations l
ON d.location_id = l.location_id;

3.2 外连接(OUTER JOIN)的实现

  • 左外连接(LEFT OUTER JOIN)
    • 语法:
# 实现查询结果是A 
# 其中LEFT后面的OUTER可以省略
SELECT 字段列表 FROM A表 LEFT OUTER JOIN B表 ON 关联条件 WHERE 等其他子句;
  • 举例:
SELECT last_name, department_name
FROM employees e LEFT JOIN departments d
ON e.department_id = d.department_id;
  • 右外连接(RIGHT OUTER JOIN)
    • 语法:
# 实现查询结果是B
# 其中RIGHT后面的OUTER可以省略
SELECT 字段列表 FROM A表 RIGHT OUTER JOIN B表 ON 关联条件 WHERE 等其他子句;
  • 举例:
SELECT last_name, department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id = d.department_id;
  • 满外连接(FULL OUTER JOIN)
    • 语法:
# 实现查询结果是A和B
SELECT 字段列表 FROM A表 FULL JOIN B表 ON 关联条件 WHERE 等其他子句;
  • 举例:
SELECT last_name, department_name
FROM employees e FULL JOIN departments d
ON e.department_id = d.department_id;
  • 满外连接的结果 = 左右表匹配的数据 + 左表没有匹配到的数据 + 右表没有匹配到的数据
  • SQL99是支持满外连接的。使用FULL JOIN 或 FULL OUTER JOIN来实现
  • 需要注意的是,MySQL不支持FULL JOIN,但是可以用 LEFT JOIN UNION RIGHT join代替

4. UNION的使用

  • 合并查询结果 利用UNION关键字,可以给出多条SELECT语句,并将它们的结果组合成单个结果集
  • 语法格式:
SELECT column,... FROM table1 
UNION [ALL] 
SELECT column,... FROM table2
  • UNION操作符
  • UNION ALL操作符

5. 7种SQL JOINS的实现

5.1 如下图7种形式:

# 中图: 内连接
SELECT employee_id, department_name
FROM employees e JOIN departments d
ON e.department_id = d.department_id; 

# 左上图: 左外连接
SELECT employee_id, department_name
FROM employees e LEFT JOIN departments d
ON e.department_id = d.department_id; 

# 右上图: 右外连接
SELECT employee_id, department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id = d.department_id; 

# 左中图:
SELECT employee_id, department_name
FROM employees e LEFT JOIN departments d
ON e.department_id = d.department_id
WHERE d.department_id IS NULL;

# 右中图:
SELECT employee_id, department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id = d.department_id
WHERE e.department_id IS NULL;

# 左下图:满外连接
# 方式一: 左上图 UNION ALL 右中图
SELECT employee_id, department_name
FROM employees e LEFT JOIN departments d
ON e.department_id = d.department_id
UNION ALL
SELECT employee_id, department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id = d.department_id
WHERE e.department_id IS NULL;

# 方式二: 左中图 UNION ALL 右上图
SELECT employee_id, department_name
FROM employees e LEFT JOIN departments d
ON e.department_id = d.department_id
WHERE d.department_id IS NULL
UNION ALL
SELECT employee_id, department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id = d.department_id;

# 右下图:左中图 UNION AL 右中图
SELECT employee_id, department_name
FROM employees e LEFT JOIN departments d
ON e.department_id = d.department_id
WHERE d.department_id IS NULL
UNION ALL
SELECT employee_id, department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id = d.department_id
WHERE e.department_id IS NULL;

5.2 语法格式小结

  • 左中图
#实现A - A∩B 
select 字段列表
from A表 left join B表 
on 关联条件 
where 从表关联字段 is null and 等其他子句;
  • 右中图
#实现B - A∩B 
select 字段列表
from A表 right join B表 
on 关联条件 
where 从表关联字段 is null and 等其他子句;
  • 左下图
#实现查询结果是A∪B 
#用左外的A,union 右外的B 
select 字段列表
from A表 left join B表 
on 关联条件 
where 等其他子句 
union 
select 字段列表
from A表 right join B表 
on 关联条件 
where 等其他子句;

#实现A∪B - A∩B 或 (A - A∩B) ∪ (B - A∩B) 
#使用左外的 (A - A∩B) union 右外的(B - A∩B) 
select 字段列表
from A表 left join B表 
on 关联条件 
where 从表关联字段 is null and 等其他子句 
union 
select 字段列表
from A表 right join B表 
on 关联条件 
where 从表关联字段 is null and 等其他子句