SQL 中“过滤条件”写在 SELECT、JOIN 和 WHERE 的区别


1. SELECT 子句中的过滤

作用

SELECT 子句本身并不用于直接过滤数据行 ,而是用于表达式计算和返回结果列。

但有两种特殊"伪过滤"情况,初学者容易混淆:

a) 使用CASE WHEN生成标志位

sql 复制代码
SELECT
  id,
  amount,
  CASE WHEN amount > 500 THEN '大额' ELSE '小额' END AS grade
FROM orders;

这里只是标记,并没有"过滤"数据行。

b) 利用窗口函数的 FILTER

sql 复制代码
SELECT
  SUM(amount) FILTER (WHERE type = 'A') AS sum_a,
  SUM(amount) FILTER (WHERE type = 'B') AS sum_b
FROM orders;

这里的 FILTER 是对聚合函数的聚合过滤,不影响整行是否被选中,只决定聚合时哪些被算上。

总结

SELECT 不能直接过滤结果行 (除了各种聚合"过滤"标志)。真正过滤结果应放在 WHEREJOINHAVING


2. JOIN 子句中的过滤(ON 条件)

JOINON 部分与 WHERE 条件不同:

a) INNER JOIN

sql 复制代码
SELECT *
FROM a
JOIN b ON a.id = b.a_id AND b.status = 'active'

解析

  • b.status = 'active' 写在 ON 内,只有满足 a.id=b.a_id 且 b.status='active' 时,才产生一对结果
  • 即,在关联时,提前筛选对方表的相关数据

b) LEFT JOIN

sql 复制代码
SELECT *
FROM a
LEFT JOIN b ON a.id = b.a_id AND b.status = 'active'

解析

  • LEFT JOIN 不管 b 有无匹配,总会保留 a。
  • ON 过滤是:如果 b.status 不为 'active',则 b 列为 NULL;不会把整行 a 去掉。

c) 过滤条件写在 WHERE

sql 复制代码
SELECT *
FROM a
LEFT JOIN b ON a.id = b.a_id
WHERE b.status = 'active'

解析

  • 此写法:WHERE 条件会把 a 的那些 b 没有匹配到的(所有 b 为 NULL 的)全部去掉,实际上结果和 INNER JOIN 效果一样!

3. WHERE 子句中的过滤

WHERE 负责数据源(包括 join 后的中间结果)的最终行过滤

sql 复制代码
SELECT *
FROM a
JOIN b ON a.id = b.a_id
WHERE a.amount > 100 AND b.status = 'active'
  • 先连接,再整体过滤。

4. 典型案例对比

假如有如下两个表:

  • students(id, name)
  • scores(student_id, subject, mark)

假设每个学生有多个成绩。


场景1:只看及格成绩

条件写在JOIN:

sql 复制代码
SELECT s.id, s.name, sc.mark
FROM students s
JOIN scores sc ON s.id = sc.student_id AND sc.mark >= 60

🚩只有及格的匹配行会被连接,学生不会重复出现不及格的成绩。


条件写在WHERE:

sql 复制代码
SELECT s.id, s.name, sc.mark
FROM students s
JOIN scores sc ON s.id = sc.student_id
WHERE sc.mark >= 60

🚩结果一样:只显示及格成绩。


LEFT JOIN + 过滤条件写在JOIN:

sql 复制代码
SELECT s.id, s.name, sc.mark
FROM students s
LEFT JOIN scores sc ON s.id = sc.student_id AND sc.mark >= 60

🚩每个学生会显示所有自己及格的成绩,没及格就为 NULL,但学生都在。


LEFT JOIN + 过滤条件写在WHERE:

sql 复制代码
SELECT s.id, s.name, sc.mark
FROM students s
LEFT JOIN scores sc ON s.id = sc.student_id
WHERE sc.mark >= 60

🚩所有没及格的行(包括没考试的、sc.mark是NULL),全部被过滤掉,效果和INNER JOIN一样!

注意:LEFT JOIN+WHERE条件,在想保留主表(比如students)所有数据但只展示部分关联的情况下,要特别小心写法。


5. 总结表格

过滤条件位置 作用对象 推荐场景
SELECT 只对输出列做条件标记、赋值 需展示条件分组/标识
JOIN (ON) 只影响表之间的连接配对关系 只过滤被联接表时,主表全保留
WHERE 影响整个结果最终输出行 需要严格筛选全部输出的情况

一句话总结

  • 只保留主表相关数据LEFT JOIN ... ON ...
  • 真正只显示符合条件整行WHERE
  • 用于联表附加限定,不影响主表全保留JOIN ON
  • SELECT只做数据衍生、打标,不过滤行

相关推荐
Database_Cool_5 小时前
阿里云 Tair(企业级内存数据库)vs 腾讯云 Redis 云缓存深度对比:性能/数据结构/成本全维度 Benchmark
数据库·阿里云·缓存
流星白龙5 小时前
【Redis】1.Redis特性
数据库·redis·缓存
奶糖 肥晨5 小时前
DBeaver 安装与 MySQL 连接配置教程
数据库·mysql
woshihuanglaoshi5 小时前
数据迁移与版本管理 - Flutter在鸿蒙平台实现数据库升级策略
数据库·学习·flutter·华为·harmonyos·鸿蒙·鸿蒙系统
java_logo7 小时前
Apache Doris Docker 部署指南:实时分析数据库实战
数据库·docker·apache·doris·apache doris·轩辕镜像·docker部署doris
广州灵眸科技有限公司15 小时前
xfce桌面触摸校准:基于灵眸科技EASY-EAl-Orin-Nano
数据库·windows·科技
憧憬成为web高手17 小时前
皮卡丘靶场速通--sql 2
数据库·sql·mybatis
段一凡-华北理工大学17 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
oradh19 小时前
Oracle XTTS实现跨版本迁移和升级(Oracle 11g单库升级至19C RAC集群)
数据库·oracle·11g升级19c·xtts跨版本迁移和升级
z1234567898620 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程