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

两张表关联查询,查询条件什么时候加到on上,什么时候加到where上面(过滤右表的条件应写在 ON 子句中,以保留左表所有行)

SELECT adc.ID AS county_id, NVL(stats.shouldReport, 0) AS shouldReport, -- 应报企业数 NVL(stats.reported, 0) AS reported, -- 已报企业数(没填就是 0) ROUND( NVL(stats.reported, 0) / NULLIF(NVL(stats.shouldReport, 1), 0), 4 ) AS report_rate -- 填报率 FROM ACIM_DIC_COUNTY adc LEFT JOIN ( -- 核心统计:每个区的应报数和已报数 SELECT oewrt.COUNTY_ID, COUNT(*) AS shouldReport, -- 所有已备案企业 COUNT(oemr.RECORD_ID) AS reported -- 只统计填了月报的 FROM OIL_ENTER_WHSLEWHSE_RECORD_TAB oewrt LEFT JOIN OIL_ENTER_MONTH_REPORT oemr ON oewrt.id = oemr.RECORD_ID AND oemr.MONTH = '2025-09' -- ✅ 关键:条件在 ON WHERE oewrt.ENT_TYPE IN ('1', '3') AND oewrt.CONFIRM_STATUS = '2' GROUP BY oewrt.COUNTY_ID ) stats ON adc.ID = stats.COUNTY_ID WHERE shouldReport > 0 ; -- 或 SUBSTR('910101', 1, 2) || '%'

为什么AND oemr.MONTH = '2025-06'写在ON上“不过滤左表”,而写在WHERE上就“过滤掉左表行”?


🧠 核心原因:ONWHERE在 SQL 执行流程中的作用完全不同

✅ SQL 的逻辑执行顺序(简化版):
  1. FROM+JOIN→ 先把两张表“拼”成一张大表
    • 这个阶段由ON条件决定哪些右表行能和左表匹配
  2. WHERE→ 对上一步生成的大表进行行级过滤
  3. GROUP BY,SELECT,ORDER BY...

🔑ON控制“怎么连”,WHERE控制“连完后留哪些”


🌰 举个具体例子

假设数据如下:

左表:企业表(oewrt)
idCOUNTY_IDENT_TYPECONFIRM_STATUS
1A12
2B12
右表:月报表(oemr)
RECORD_IDMONTH
12025-06
12025-05

企业 B 没有 2025-06 月报!


情况一:条件写在ON(✅ 正确保留左表)

SELECT * FROM oewrt LEFT JOIN oemr ON oewrt.id = oemr.RECORD_ID AND oemr.MONTH = '2025-06';

执行过程:

  1. 对左表每一行,找右表中同时满足id=RECORD_IDMONTH='2025-06'的行
  2. 结果:
    idCOUNTY_IDRECORD_IDMONTH
    1A12025-06
    2BNULLNULL

左表所有行都在,只是右表匹配不到就填NULL


情况二:条件写在WHERE(❌ 过滤掉左表)

SELECT * FROM oewrt LEFT JOIN oemr ON oewrt.id = oemr.RECORD_ID WHERE oemr.MONTH = '2025-06';

执行过程:

  1. 先做LEFT JOIN(不带 MONTH 条件):
    idCOUNTY_IDRECORD_IDMONTH
    1A12025-06
    1A12025-05
    2BNULLNULL
  2. 再执行WHERE oemr.MONTH = '2025-06'
    • 第一行:2025-06 = 2025-06→ ✅ 保留
    • 第二行:2025-05 = 2025-06→ ❌ 过滤
    • 第三行:NULL = 2025-06→ ❌UNKNOWN(不是 true),被过滤!

最终结果:

idCOUNTY_IDRECORD_IDMONTH
1A12025-06

企业 B 完全消失了!


📌 关键区别总结

条件在ON条件在WHERE
作用阶段连接时(决定右表哪些行能匹配)连接后(对整行做过滤)
对左表影响永不丢左表行(LEFT JOIN 语义)会丢左表行(如果右表为 NULL)
NULL 处理允许右表为 NULLNULL = 'xxx'→ false/unknown → 被过滤
适用场景需要保留左表所有记录(如你的需求)只要匹配成功的记录(相当于 INNER JOIN)

💡 一句话记住:

ON是“连接规则”,WHERE是“生存规则”。
左连接中,左表行天生“存活”;但如果WHERE判它“死刑”(比如要求右表字段等于某值,但它却是 NULL),它就会被干掉。

✅ 正确认知(精炼版):

当使用LEFT JOIN时:

  • 过滤右表的条件应写在ON子句中,以保留左表所有行;
  • COUNT(右表.某字段)(如主键)来统计右表实际匹配的记录数
  • 因为COUNT(字段)会自动忽略NULL值,所以未匹配的行不会被计入,结果就是“有效关联数”。

📌 举个标准模式(你的场景)

SELECT a.COUNTY_ID, COUNT(*) AS shouldReport, -- 左表总行数(含未匹配) COUNT(b.RECORD_ID) AS reported -- 右表非 NULL 行数(自动排除未匹配) FROM OIL_ENTER_WHSLEWHSE_RECORD_TAB a LEFT JOIN OIL_ENTER_MONTH_REPORT b ON a.id = b.RECORD_ID AND b.MONTH = '2025-06' -- ✅ 右表过滤条件放 ON WHERE a.ENT_TYPE IN ('1','3') AND a.CONFIRM_STATUS = '2' GROUP BY a.COUNTY_ID;

✅ 这样:

  • 每个有备案企业的区都会出现;
  • reported自动 = 填了 2025-06 月报的企业数(没填的就是 0);
  • 不需要WHERE b.MONTH = ...,否则会丢数据!

⚠️ 但要注意两个细节(避免误解)

1. ❌ 不是“把 null 去掉从而统计总数”,而是:
  • COUNT(*)→ 统计所有行(包括右表为 NULL 的)
  • COUNT(b.xxx)→ 统计b.xxx 非 NULL 的行

所以你不是“去掉 null 再统计总数”,而是分别统计“总行数”和“有效关联行数”

2. ✅ 字段选择很重要:
  • 推荐用COUNT(b.RECORD_ID)COUNT(b.id)(右表主键/非空字段)
  • 避免用COUNT(b.MONTH),万一MONTH本身允许为 NULL(即使有记录),也会被忽略

🔁 对比错误做法

-- ❌ 错误:条件放 WHERE LEFT JOIN b ON a.id = b.RECORD_ID WHERE b.MONTH = '2025-06'

→ 未填报的企业整行消失,COUNT(*)COUNT(b.xxx)都只算填报的,且无填报的区不出现

-- ❌ 错误:用 COUNT(*) COUNT(*) AS reported -- 即使没匹配,也会计 1!

→ 因为LEFT JOIN后每行都存在,COUNT(*)永远 = 左表行数。


✅ 总结口诀(背下来!)

左连要保左,右表条件放 ON;
统计匹配数,COUNT(右表字段);
若用 WHERE 滤,左表数据全丢光;
COUNT(*) 是总数,别拿它当已报量。


你现在完全掌握了这个关键技巧!👏
只要记住:ON控连接,WHERE控生死,COUNT(字段)忽略 NULL,就能写出正确的统计 SQL。

http://www.cnnetsun.cn/news/4165.html

相关文章:

  • PHP扩展开发实战:生命周期管理与性能优化全解析
  • Vue网络图组件终极指南:如何用v-network-graph快速创建交互式数据可视化
  • Marketch插件终极指南:从设计稿到代码的无缝转换
  • Wabbajack:游戏模组自动化安装的革命性解决方案
  • TinyTeX终极指南:轻量级LaTeX排版系统快速上手
  • 深入理解前端体系:为什么 DOM 属于 BOM,我们却要先学 DOM?
  • AI 硬件助手:LLM的比较推理与自动化决策理由生成
  • 文件格式转换工具:数据序列化、Web Worker与离线数据处理
  • 光学镜头光心与AA工艺
  • INT(In-band Network Telemetry,带内网络遥测)技术
  • 终极色彩管理方案:Sketch Palettes让设计效率翻倍
  • DevUI 组件生态:从入门到企业级实战
  • 3步搭建PostHog:开源用户行为分析平台完全指南
  • Shortkeys浏览器快捷键定制工具:从入门到精通完整指南
  • 地籍测绘效率革命:告别繁琐的分割计算
  • 7、Qt绘图与打印全解析
  • Node.js FCM推送库:构建高效实时消息系统的终极解决方案
  • 掘进机定向“磁”场困局?这款MEMS寻北仪给出了“零干扰”的终极答案
  • Wan2.2-T2V-A14B支持长视频生成,解决行业痛点
  • Switch自定义终极指南:aio-switch-updater完全解决方案
  • TradingView金融数据自动化采集工具:高效构建机器学习数据集
  • Sketch Measure插件完整教程:快速掌握设计规范生成技巧
  • 游戏AI自动化框架GameAISDK:让游戏测试变得更智能 [特殊字符]
  • Smith圆图工具V4.1.0.0终极指南:电子工程师的阻抗匹配利器
  • TVM测试框架实战指南:从入门到精通
  • 建议12月准备面试前端,还没计划的…
  • 在keil中为什么不勾选微库 (MicroLib)使用printf()会程序卡死?
  • Hermes引擎内存管理终极指南:从原理到实战优化
  • 电子围栏与GEO优化软件:中低频商家突破困境的利器?精准触达客户实现业绩增长!
  • Wan2.2-T2V-A14B能否生成带有字幕的视频?