今天我们来详细探讨一下 MySQL 中的“全连接”概念。
这是一个非常重要的话题,因为 MySQL 的一个显著特点是:它不支持标准的 `FULL OUTER JOIN`(全外连接)语法。但这并不意味着无法实现全连接的效果,我们需要通过其他方式模拟。
一、 核心概念:什么是全连接 (FULL OUTER JOIN)?
全连接的目的是返回两个表中的所有记录。它会将匹配的行进行连接,同时也会返回两个表中没有匹配到的行。对于未能匹配的部分,结果集中会用 `NULL` 填充。
2. 左表中未与右表匹配的行 (右表字段用 NULL 填充)
3. 右表中未与左表匹配的行 (左表字段用 NULL 填充)
既然 MySQL 不支持 `FULL OUTER JOIN`,我们使用 `LEFT JOIN`、`RIGHT JOIN` 和 `UNION` 操作符来模拟它。
(SELECT ... FROM table1 LEFT JOIN table2 ON ...)
(SELECT ... FROM table1 RIGHT JOIN table2 ON ...);
为什么用 `UNION` 而不是 `UNION ALL`?
* `UNION ALL` 会保留所有行,包括重复的。
* 内连接的部分在左连接和右连接的结果中都会出现,是重复的,所以这里通常使用 `UNION` 来去重。
假设我们有两个简单的表:`customers` (客户) 和 `orders` (订单)。
|-------------|----------|
| order_id | amount | customer_id |
|----------|--------|-------------|
| 103 | 22.80 | 99 | -- 一个“孤儿”订单,客户ID在客户表中不存在
我们的目标是得到一个全连接的结果,显示所有客户和所有订单的关联情况。
LEFT JOIN orders o ON c.customer_id = o.customer_id;
| customer_id | name | order_id | amount |
|-------------|---------|----------|--------|
| 1 | Alice | 101 | 50.00 |
| 2 | Bob | 102 | 75.50 |
| 3 | Charlie | NULL | NULL | <- 没有订单的客户
获取所有订单及其客户(包括没有对应客户的“孤儿”订单)。
RIGHT JOIN orders o ON c.customer_id = o.customer_id;
| customer_id | name | order_id | amount |
|-------------|---------|----------|--------|
| 1 | Alice | 101 | 50.00 |
| 2 | Bob | 102 | 75.50 |
| NULL | NULL| 103 | 22.80 | <- 没有客户的订单
将左连接和右连接的结果合并,并通过 `UNION` 去除中间重复的内连接部分(Alice 和 Bob 的记录)。
-- 左连接:获取所有客户+他们的订单(客户为主)
LEFT JOIN orders o ON c.customer_id = o.customer_id
-- 右连接:获取所有订单+他们的客户(订单为主)
RIGHT JOIN orders o ON c.customer_id = o.customer_id
| customer_id | name | order_id | amount |
|-------------|---------|----------|--------|
| 1 | Alice | 101 | 50.00 | <- 内连接部分
| 2 | Bob | 102 | 75.50 | <- 内连接部分
| 3 | Charlie | NULL | NULL | <- 仅左表有
| NULL | NULL| 103 | 22.80 | <- 仅右表有
这个结果完美地展示了全连接的效果:匹配的行 + 仅左表存在的行 + 仅右表存在的行。
1. 性能: 全连接实际上是执行两次查询(一次左连接,一次右连接)然后合并结果。对于大表,这可能会产生性能问题。务必确保连接条件(`ON` 子句)上的字段已建立索引。
2. 列的一致性: 在 `UNION` 的两部分查询中,`SELECT` 的字段数量和数据类型必须严格一致。通常建议明确指定字段名而不是使用 `SELECT *`。
3. WHERE 子句的位置: 如果需要对最终结果进行过滤,可以将整个 `UNION` 查询作为一个子查询,然后在外部进行 `WHERE` 筛选。
(SELECT ... LEFT JOIN ...)
(SELECT ... RIGHT JOIN ...)
WHERE full_result.amount > 100;
4. 别名的使用: 为 `UNION` 后的计算字段或整个派生表起一个别名,可以让外部查询更容易引用。
| 全连接 (FULL OUTER JOIN) | 不支持原生语法 |
| 模拟全连接 | 使用 `LEFT JOIN` 和 `RIGHT JOIN` 的 `UNION` |
| 关键点 | 使用 `UNION` 来自动去重,保持左右查询的列结构一致 |
虽然需要多写一些代码,但通过 `UNION` 来组合左连接和右连接,是 MySQL 中实现全连接功能的标准且有效的方法。
另外搭配便捷的MYSQL备份工具,可定时备份、异地备份,MYSQL导出导入。可本地连接LINUX里的MYSQL,简单便捷。可以大大地提高工作效率喔。