一、JOIN 类型场景对比表(通用业务场景,不限资产系统)
1. 四种 JOIN 适用场景、语法规则、数据保留规则对比
| 连接类型 | 核心使用场景 | 过滤条件标准位置 | 数据保留规则 | 典型业务示例 |
|---|---|---|---|---|
| LEFT JOIN左连接 | 1. 查询主表全部数据,附表有值就展示,无则空2. 台账、全量报表、统计汇总3. 必须保证主表条数完整 | 附表筛选条件写在 ON 后主表筛选写 WHERE |
左表所有行 100% 保留;右表无匹配则字段为 NULL | 1. 全部商品 + 对应订单(无订单商品也要展示)2. 全部资产 + 所属部门3. 所有员工 + 考勤记录 |
| INNER JOIN内连接 | 1. 只查询两边都存在匹配的数据2. 精确筛选、交叉关联查询 | ON / WHERE 放过滤效果一致 | 仅保留左右表能互相匹配的行,缺一边直接丢弃 | 1. 有订单的商品列表2. 有归属部门的资产清单3. 已签到员工 |
| RIGHT JOIN右连接 | 1. 以右表为主体,展示右表全部数据2. 极少使用,等价调换左右表 LEFT JOIN | 左表筛选写在 ON 后 |
右表全部保留,左表无匹配则 NULL | 全部分类 + 对应商品(无商品分类也要展示) |
| FULL JOIN全连接(MySQL 不支持) | 左右表所有数据全部展示,无匹配补 NULL | - | 左右表数据全部保留 | 库存商品 + 线下订单(两边独立数据都展示) |
2. LEFT JOIN 条件放置对比表(本次问题核心)
| 写法 | 过滤条件位置 | 执行逻辑 | 结果影响 | 适用场景 |
|---|---|---|---|---|
| 标准正确写法 | 附表过滤写 ON 子句 |
关联时先过滤附表有效数据,匹配不到仍保留主表 | 主表数据完整,不会丢失行数 | 全量台账、统计报表、首页汇总 |
| 错误踩坑写法 | 附表过滤写外层 WHERE |
关联完成后再过滤,NULL 不满足等值条件,整行删除 | 主表大量数据丢失,统计数量缩水 | 禁止用于需要全量数据的查询 |
二、通用可复用示例(商品 + 订单 案例)
基础表说明
-- 主表:商品表(左表,需要全部保留)
product(id, name, price, del_flag)
-- 附表:订单表(右表,一对多,存在已删除订单)
order(id, product_id, order_time, del_flag)
示例 1:LEFT JOIN 正确写法(附表过滤放 ON,商品全量展示)
需求:查询所有商品,带出有效订单,无订单商品也要显示
SELECT p.*, o.order_time
FROM product p
LEFT JOIN `order` o
ON p.id = o.product_id
AND o.del_flag = 0 -- 附表删除过滤写ON,只匹配有效订单
WHERE p.del_flag = 0; -- 仅主表过滤放WHERE
逻辑:所有未删除商品全部查出,订单已删 / 无订单时 order_time 为 NULL,行数不会变少。
示例 2:LEFT JOIN 错误写法(附表过滤放 WHERE,数据丢失)
SELECT p.*, o.order_time
FROM product p
LEFT JOIN `order` o ON p.id = o.product_id
WHERE p.del_flag = 0 AND o.del_flag = 0; -- 订单过滤写WHERE
问题:没有订单的商品 o.del_flag 是 NULL,NULL=0 不成立,无订单商品全部被过滤,统计数量变少。
示例 3:INNER JOIN(仅查询有有效订单的商品)
SELECT p.*, o.order_time
FROM product p
INNER JOIN `order` o
ON p.id = o.product_id AND o.del_flag = 0
WHERE p.del_flag = 0;
逻辑:只保留存在有效订单的商品,无订单商品直接丢弃,适合精确筛选。
示例 4:一对多去重(避免一条商品多条订单导致行数翻倍)
SELECT DISTINCT p.*, o.order_time
FROM product p
LEFT JOIN (
-- 子查询提前去重,一个商品只取一条订单
SELECT DISTINCT product_id, order_time FROM `order` WHERE del_flag = 0
) o ON p.id = o.product_id
WHERE p.del_flag = 0;
三、JOIN 关联通用注意事项(全场景通用规范)
1. LEFT JOIN 硬性规范(台账 / 报表必看)
- 只要需要完整主表数据 ,一律使用
LEFT JOIN; - 附表的删除标记、状态、业务过滤条件,必须写在 ON 后面;
- 外层
WHERE只能放主表的筛选条件,禁止判断右表字段(=、!=、IN 等)。
2. 关联匹配坑点
- 文本名称关联极易匹配失败 不要用名称、字符串做关联键(如部门名称、商品名称),优先数字 ID 关联;字符集、空格、特殊符号、大小写都会导致匹配失效,出现大量 NULL。
- 一对多表笛卡尔积重复 主表 1 条数据匹配附表 N 条,查询总行数会虚高;统计总数用
COUNT(DISTINCT 主表主键),展示列表用子查询 DISTINCT 去重附表。
3. UNION ALL 多表合并规范
- 多个子查询字段顺序、字段类型必须一一对应;
- 空值统一用
NULL,不要混用空字符串''; - 关联 JOIN 使用的字段别名全局统一,避免关联匹配错乱。
4. 多表嵌套语法规范
- 不写冗余多层括号嵌套 JOIN,每条 LEFT JOIN 单独换行,层级清晰;
- 多表关联顺序:主表在前,一对多附表靠后,减少笛卡尔积。
5. 快速判断口诀
- 要全部数据用 LEFT JOIN,附表过滤放 ON;
- 只要匹配数据用 INNER JOIN,过滤放哪都可以;
- WHERE 中不要判断 LEFT JOIN 右侧表字段;
- 关联优先数字 ID,杜绝名称文本匹配;
- 一对多附表先去重,统计计数必加 DISTINCT。