当前位置: 首页 > 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;
http://www.xdnf.cn/news/434593.html

相关文章:

  • 在服务器排查java某个线程导致CPU飙高教程
  • 前端实用工具|JavaScript 身份证号合法性校验工具类全解析
  • openFeign远程调用
  • 需求跟踪矩阵准确性的5大策略
  • 基于vllm-ascend的华为atlas大模型部署
  • OrangePi Zero 3学习笔记(Android篇)8 - OpenOCD
  • 什么是原码和补码
  • 【JavaScript】JavaScript实现大数相乘
  • ebook2audiobook开源程序使用动态 AI 模型和语音克隆将电子书转换为带有章节和元数据的有声读物。支持 1,107+ 种语言
  • day013-软件包管理-实战
  • 门禁人脸识别系统详细技术文档
  • 索尼(sony)摄像机格式化后mp4的恢复方法
  • 【基础】Windows开发设置入门2:Windows 终端Windows Terminal
  • FHQ平衡树
  • MCP Server多节点滚动升级一致性治理
  • 怎样将课程表导入手机日历,每天提醒上课?
  • 【Linux系列】dd 命令的深度解析与应用实践
  • Spring框架请求注解
  • 从生产流程到故障处理,R²AIN SUITE 如何为制造业“减负”?
  • Transformer架构介绍+从零搭建预训练模型项目
  • ai讲ping
  • 【C盘空间不足怎么办】
  • git merge和git rebase
  • 科学养生:构建现代健康生活新范式
  • LamaIndex rag(增强检索)入门
  • MySQL:关系模型的基本理论
  • 以价值为导向的精准数据治理实践,赋能业务决策
  • 基于STM32、HAL库的SGTL5000XNLA3R2音频接口芯片驱动程序设计
  • 数据库--处理模型(Processing Model)
  • DCDC输入4.5V-65V耐压 5A电流异步降压芯片SL3075兼容替换TPS54560