一、LEFT JOIN(左连接)详解
核心机制
-
保留左表所有行:无论右表是否有匹配记录
-
匹配右表数据:当匹配成功时,合并左右表数据
-
NULL 填充:当右表无匹配时,右表字段用 NULL 填充
-
一对多关系:左表一行可能对应右表多行
完整语法
SELECT 列列表
FROM 左表
LEFT [OUTER] JOIN 右表
ON 连接条件
[WHERE 过滤条件];
执行流程
从左表取第一行
扫描右表所有行,寻找满足 ON 条件的记录
找到匹配:合并行加入结果集
未找到匹配:左表数据 + 右表 NULL 值加入结果集
重复上述过程处理左表所有行
典型应用场景
主从关系查询:
-- 所有产品及其销售记录(包括无销售的产品)
SELECT p.product_id, p.name, s.sale_date, s.quantity
FROM products p
LEFT JOIN sales s ON p.product_id = s.product_id;
查找缺失数据:
-- 从未被订购的产品
SELECT p.product_id, p.name
FROM products p
LEFT JOIN orders o ON p.product_id = o.product_id
WHERE o.order_id IS NULL;
层级结构展示:
-- 所有部门及其员工(包括空部门)
SELECT d.department_name, e.employee_name
FROM departments d
LEFT JOIN employees e ON d.department_id = e.department_id;
注意事项
ON vs WHERE:
ON 条件决定如何连接
WHERE 条件在连接后过滤结果
-- 错误:会过滤掉没有订单的客户
SELECT c.name, o.order_date
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
WHERE o.order_date > '2023-01-01';
--WHERE子句在LEFT JOIN后执行,会强制将不满足条件的右表记录(包括NULL记录)过滤掉
--导致没有2023年后订单的客户会被排除,LEFT JOIN退化为INNER JOIN
--最终结果丢失了没有订单的客户记录,
--简述,如果放在where里面,就是在新生成表里面过滤,
-- 正确:将日期条件放在ON中
SELECT c.name, o.order_date
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
AND o.order_date > '2023-01-01';
--过滤条件作为连接条件的一部分,在JOIN过程中应用
--保留所有客户记录,仅过滤关联的订单记录
--没有匹配订单的客户会显示为NULL,但客户信息仍然保留
--简述,如果放在on里面,就是在 left后面的旧的orders表里面进行筛选,不会影响到另外一个表
多表连接顺序:
SELECT *
FROM A
LEFT JOIN B ON A.id = B.a_id
LEFT JOIN C ON B.id = C.b_id;
性能优化:
在连接列上建立索引
避免在 ON 条件中使用函数
限制 SELECT 的列数
二、RIGHT JOIN(右连接)详解
核心机制
-
保留右表所有行:无论左表是否有匹配记录
-
匹配左表数据:当匹配成功时,合并左右表数据
-
NULL 填充:当左表无匹配时,左表字段用 NULL 填充
-
镜像操作:实质是 LEFT JOIN 的逆向操作
完整语法
SELECT 列列表
FROM 左表
RIGHT [OUTER] JOIN 右表
ON 连接条件
[WHERE 过滤条件];
执行流程
从右表取第一行
扫描左表所有行,寻找满足 ON 条件的记录
找到匹配:合并行加入结果集
未找到匹配:右表数据 + 左表 NULL 值加入结果集
重复上述过程处理右表所有行
典型应用场景
逆向主从关系:
-- 所有订单及其客户(强调订单为主体)
SELECT o.order_id, o.amount, c.name
FROM customers c
RIGHT JOIN orders o ON c.id = o.customer_id;
查找孤立数据:
-- 系统中未关联客户的订单
SELECT o.order_id, o.order_date
FROM customers c
RIGHT JOIN orders o ON c.id = o.customer_id
WHERE c.id IS NULL;
数据完整性检查:
-- 检查任务分配情况
SELECT t.task_name, e.employee_name
FROM employees e
RIGHT JOIN tasks t ON e.id = t.assigned_to;
三、注意事项
可替代性:
-- 以下两个查询等价
SELECT *
FROM A
RIGHT JOIN B ON A.id = B.a_id;
SELECT *
FROM B
LEFT JOIN A ON B.a_id = A.id;
使用频率:
实际开发中 RIGHT JOIN 使用率不足 5%
主要因不符合从左到右的思维习惯
复杂查询中可能降低可读性
特殊场景价值:
当右表是查询主体时更直观
某些数据库优化器对特定写法有优化
四、LEFT JOIN 与 RIGHT JOIN 深度对比
特性 | LEFT JOIN | RIGHT JOIN |
---|---|---|
主表 | FROM 后的第一个表 | JOIN 后的第二个表 |
保留行 | 左表所有行 | 右表所有行 |
未匹配处理 | 右表字段填充 NULL | 左表字段填充 NULL |
使用频率 | 非常高 (约95%场景) | 较低 (约5%场景) |
可读性 | 符合自然阅读顺序 | 需要逆向思维 |
等价转换 | A LEFT JOIN B ≡ B RIGHT JOIN A | A RIGHT JOIN B ≡ B LEFT JOIN A |
典型应用 | 获取主体信息+关联补充数据 | 强调从表信息完整性 |
NULL 检测 | WHERE right_table.id IS NULL | WHERE left_table.id IS NULL |