写联表查询SQL时筛选条件写在where 前面和后面有啥区别
写联表查询SQL时筛选条件写在where 前面和后面有啥区别
ON
条件作用于「表连接阶段」,WHERE
条件作用于「连接完成后的结果集过滤阶段」,二者在逻辑执行顺序、对连接结果的影响上完全不同
一、先明确你的 SQL 中「条件的当前位置」
你的 SQL 里存在两类筛选条件,先对应到「ON 前 / 后」的概念:
条件位置 | 具体条件 | 作用阶段 |
---|---|---|
JOIN 的 ON 子句中 | rel.id = ord.bidding_indicator_release_id (连接条件)、ord.del_flag = 'N' 、cate.review_status != 'shbh' | 表连接阶段 |
WHERE 子句中 | rel.del_flag = 'N' 、rel.release_status = 'yjcj' | 连接后结果集过滤 |
下面通过「把 ON 中的条件移到 WHERE 后」和「把 WHERE 中的条件移到 ON 中」的对比,说明核心差异。
二、核心区别:作用阶段与对连接结果的影响
1. 对「左连接(LEFT JOIN)」的影响(最关键!)
你的 SQL 用了 LEFT JOIN
(左表是 bidding_indicator_release_info rel
,右表是 ord
和 cate
)。左连接的核心规则是:左表的所有记录都会保留,右表只保留满足 ON 条件的记录;右表不满足条件的记录,字段值会填充为 NULL。
这时候,「条件写在 ON 还是 WHERE」会直接决定右表记录是否保留,甚至影响左表记录的最终结果:
案例 1:ord.del_flag = 'N'
写在 ON 中 vs 写在 WHERE 中
写在 ON 中(当前写法):
左连接时,只匹配ord
表中del_flag = 'N'
的记录。如果rel
表某条记录没有对应的ord
记录(或ord
记录del_flag = 'Y'
),ord
相关字段(如user_id
、price
)会填充为 NULL,但rel
表的这条记录会保留。移到 WHERE 中:
左连接先保留rel
的所有记录(包括没有对应ord
的记录),连接完成后,再用WHERE ord.del_flag = 'N'
过滤结果集。
但此时,rel
表中没有对应ord
的记录,ord.del_flag
是 NULL,而NULL = 'N'
不成立,所以 这些rel
记录会被过滤掉,最终效果等同于「内连接(INNER JOIN)」,左表的 “左连接特性” 失效。
案例 2:cate.review_status != 'shbh'
写在 ON 中 vs 写在 WHERE 中
同理,cate
是通过 LEFT JOIN
关联到 ord
的:
写在 ON 中:
只匹配cate
表中review_status != 'shbh'
的记录。如果ord
没有对应cate
记录(或cate
的review_status = 'shbh'
),cate
相关字段(ship_info_id
、ship_name
)会填充为 NULL,但rel
和ord
的记录会保留。移到 WHERE 中:
连接完成后过滤cate.review_status != 'shbh'
,此时cate
字段为 NULL 的记录(无对应cate
或review_status = 'shbh'
)会被过滤,导致rel
和ord
的记录也被删除,破坏左连接逻辑。
2. 对「内连接(INNER JOIN)」的影响(差异较小)
如果你的 SQL 是 INNER JOIN
(只保留左右表都匹配的记录),那么「条件写在 ON 还是 WHERE」最终结果可能相同,但逻辑执行顺序不同:
ON
条件:先过滤右表,再和左表做内连接(减少连接的数据量,效率可能更高);WHERE
条件:先做内连接(保留所有匹配记录),再过滤结果集(连接的数据量更大,效率可能更低)。
但你的 SQL 是 LEFT JOIN
,所以内连接的场景不适用,核心差异还是集中在左连接的记录保留逻辑上。
3. 对「左表(rel)的过滤条件」的影响
你的 WHERE
中有 rel.del_flag = 'N'
和 rel.release_status = 'yjcj'
,这些是对左表 rel
的过滤条件。如果把它们移到 LEFT JOIN rel ON ...
中(假设 rel
是其他表的右表,但你的 SQL 中 rel
是主表,没有左表):
- 若
rel
是主表(FROM 后的表),过滤条件只能写在WHERE
中(因为主表没有 ON 条件); - 若
rel
是被连接的右表(如A LEFT JOIN rel ON ...
),则rel.del_flag = 'N'
写在 ON 中,会保留 A 表所有记录,只匹配 rel 满足条件的记录;写在 WHERE 中,会过滤掉 A 表中没有匹配 rel 或 rel 不满足条件的记录,等同于内连接。
三、总结:你的 SQL 中条件位置的「正确与否」
结合业务需求(通常左连接是为了保留主表 rel
的所有有效记录,同时关联右表的匹配数据),你的 SQL 中条件位置大部分合理,但有一个细节需要注意:
条件 | 当前位置 | 是否合理? |
---|---|---|
rel.id = ord.id | ON | 合理:连接条件必须写在 ON 中,否则无法关联两表。 |
ord.del_flag = 'N' | ON | 合理:保留 rel 所有有效记录,只关联 ord 未删除的记录(无效 ord 显示 NULL)。 |
cate.review_status!='shbh' | ON | 合理:保留 ord 记录,只关联 cate 未被驳回的记录(无效 cate 显示 NULL)。 |
rel.del_flag = 'N' | WHERE | 合理:过滤主表 rel 未删除的记录(主表过滤只能写在 WHERE)。 |
rel.release_status='yjcj' | WHERE | 合理:过滤主表 rel 已竞价成交的记录(主表过滤只能写在 WHERE)。 |
四、关键口诀
判断条件写在 ON 还是 WHERE,记住这 2 条:
- 连接条件(如 A.id = B.a_id)必须写在 ON 中,否则无法建立表关联;
- 左连接中,想保留左表所有记录 → 右表的过滤条件写在 ON 中;想过滤掉左表中无右表匹配的记录 → 右表的过滤条件写在 WHERE 中(等同于内连接);
- 主表(FROM 后的表)的过滤条件,只能写在 WHERE 中(主表没有 ON 条件,写在 ON 中无效)。