当前位置: 首页 > news >正文

SQL易混点:你知道ON 和 WHERE 的区别吗

目录

文章目标

🧩 背景回顾:SQL 的执行顺序

示例对比

✅ ON 应该只管:这两行能不能配对

✅ 正确做法:把过滤放在 WHERE 

🔬 实验演示:ON vs. WHERE 的影响

总结:

 🏁 最终推荐 SQL 写法


文章目标

我们要解决的问题是:

在 JOIN 查询中,哪些条件写在 ON 后面,哪些写在 WHERE 后面?为什么?

这个问题,初看像语法细节,实则深藏两个重要概念:

  • SQL 执行顺序(JOIN → WHERE)

  • 条件的语义(配对 vs. 过滤)

🧩 背景回顾:SQL 的执行顺序

在一条 SQL 中,执行步骤大致如下:

  1. FROMJOIN:把多个表合并,按 ON 的规则配对行

  2. WHERE:对配对成功的行进行行级过滤

  3. GROUP BY:对通过筛选的行进行分组

  4. SELECT:选出你需要的字段

  5. ORDER BY / LIMIT

所以:

ON 作用在连接阶段,是“决定哪些行要配成一对”

WHERE 是后续过滤,是“已经 JOIN 上了,选谁要留下” 

示例对比

我们仍以Leecode上的一道题来分析。这道题的思路讲解可以看我之前的文章:

思路解析:第一性原理解 SQL-CSDN博客

表: Activity

+----------------+---------+
| Column Name    | Type    |
+----------------+---------+
| machine_id     | int     |
| process_id     | int     |
| activity_type  | enum    |
| timestamp      | float   |
+----------------+---------+

 

该表展示了一家工厂网站的用户活动。
(machine_id, process_id, activity_type) 是当前表的主键(具有唯一值的列的组合)。
machine_id 是一台机器的ID号。
process_id 是运行在各机器上的进程ID号。
activity_type 是枚举类型 ('start', 'end')。
timestamp 是浮点类型,代表当前时间(以秒为单位)。
'start' 代表该进程在这台机器上的开始运行时间戳 , 'end' 代表该进程在这台机器上的终止运行时间戳。
同一台机器,同一个进程都有一对开始时间戳和结束时间戳,而且开始时间戳永远在结束时间戳前面。

现在有一个工厂网站由几台机器运行,每台机器上运行着 相同数量的进程 。编写解决方案,计算每台机器各自完成一个进程任务的平均耗时。

完成一个进程任务的时间指进程的'end' 时间戳 减去 'start' 时间戳。平均耗时通过计算每台机器上所有进程任务的总耗费时间除以机器上的总进程数量获得。

结果表必须包含machine_id(机器ID) 和对应的 average time(平均耗时) 别名 processing_time,且四舍五入保留3位小数。

以 任意顺序 返回表。(来源:Leecode)

SELECT machine_id, ROUND(AVG(t2.timestamp - t1.timestamp), 3) AS processing_time
FROM Activity t1
JOIN Activity t2ON t1.machine_id = t2.machine_idAND t1.process_id = t2.process_idAND t1.activity_type = 'start'AND t2.activity_type = 'end'
GROUP BY machine_id;

这段代码可以运行,但不严谨。原因如下:

ON 应该只管:这两行能不能配对

这些条件是合理的 ON 条件:

ON t1.machine_id = t2.machine_id
AND t1.process_id = t2.process_id

解释:我们只配同一机器、同一进程的事件,没错。

❌ 不推荐在 ON 中写:

AND t1.activity_type = 'start'
AND t2.activity_type = 'end'

为什么?

  • 你想过滤的是:t1 是 start,t2 是 end

  • 这是你的业务逻辑,不是连接逻辑

  • 放在 ON 会影响 JOIN 结果集(可能 JOIN 失败),而非只是筛选

✅ 正确做法:把过滤放在 WHERE 

FROM Activity t1
JOIN Activity t2ON t1.machine_id = t2.machine_idAND t1.process_id = t2.process_id
WHERE t1.activity_type = 'start'AND t2.activity_type = 'end'

这样写的意义是:

  • 先配对所有同机同进程的记录

  • 然后从中筛出我们感兴趣的组合(startend

🔬 实验演示:ON vs. WHERE 的影响

假设 Activity 表中有:

machine_idprocess_idactivity_typetimestamp
1101start10.0
1101end20.0
1101error15.0

如果你把 'start' / 'end' 写在 ON 中:

  • JOIN 阶段只会配出 (start, end)

  • 那些 error 就永远不会参与配对

如果你写在 WHERE 中:

  • JOIN 先配出所有 (start, end)、(start, error)、(end, error) 等

  • 然后你可以灵活过滤你关心的组合

这让 SQL 更清晰、也更灵活

总结:

  • ✳️ ON“谁和谁能配成一对?”(连接规则)

  • ✳️ WHERE“配好之后,我要不要这行?”(业务逻辑)

 🏁 最终推荐 SQL 写法

SELECT machine_id, ROUND(AVG(t2.timestamp - t1.timestamp), 3) AS processing_time
FROM Activity t1
JOIN Activity t2ON t1.machine_id = t2.machine_idAND t1.process_id = t2.process_id
WHERE t1.activity_type = 'start'AND t2.activity_type = 'end'
GROUP BY machine_id;

相关文章:

  • 软考 系统架构设计师系列知识点之杂项集萃(58)
  • JIT+Opcache如何配置才能达到性能最优
  • Spring Boot 整合 Redis 实战
  • S7-1200 PLC与梅特勒-托利多IND360称重仪表通信
  • python酒店健身俱乐部管理系统
  • 遨游5G-A防爆手机:赋能工业通信更快、更安全
  • 【Ansible】基于windows主机,采用NTLM+HTTPS 认证部署
  • Flutter小白入门指南
  • USB3.0拓展坞制作学习
  • 芯片:金线的作用
  • RDD案例数据清洗
  • Maven 动态插件配置:Profile的灵活集成实践
  • PowerShell 实现 conda 懒加载
  • 新建一个reactnative 0.72.0的项目
  • 【神经网络与深度学习】局部最小值和全局最小值
  • Python中元组(Tuple)使用详解和注意事项
  • 微服务的“导航系统”:使用Spring Cloud Eureka实现服务注册与发现
  • Qt6.5.3 windows下安装教程
  • 微信小程序的开发及问题解决
  • 力扣-226.翻转二叉树
  • 白天气温超30℃的北京,晚间下起了冰雹
  • 三亚通报救护车省外拉警报器开道旅游:违规违法,责令公司停业整顿
  • 外交部亚洲司司长刘劲松会见印度驻华大使罗国栋
  • 消费维权周报|上周涉手机投诉较多,涉拍照模糊、屏幕漏液等
  • 郑州通报“夜市摊贩收取香烟交给城管”:涉事人员停职调查
  • 农林生物安全全国重点实验室启动建设,聚焦重大有害生物防控等