黄仕先 發表於 2025-12-9 22:07:00

MySQL 筛选条件放 ON 后 vs 放 WHERE 后

<p><span id="cke_bm_253S"></span>今天我们来讲讲数据库筛选条件放 <strong>ON</strong> 后和放 <strong>WHERE</strong> 后的区别。</p>
<p><strong>ON</strong> 决定如何 "连接" 表,<strong>WHERE</strong> 决定连接后 "显示" 哪些行。 这个根本区别导致了在 <strong>LEFT JOIN</strong> / <strong>RIGHT JOIN</strong> 外连接中,条件放置位置会产生巨大影响;而在 <strong>INNER JOIN</strong> 中,效果通常&nbsp;<strong>等价</strong>。</p>
<p><strong>ON</strong> 条件匹配&nbsp;<strong>被驱动表&nbsp;</strong>的行,生成 "临时关联结果集"。LEFT JOIN 会保留 <strong>驱动表&nbsp;</strong>所有行,匹配不上的 <strong>被驱动表</strong> 字段填充为 <strong>NULL</strong>。</p>
<p><strong>WHERE </strong>会对&nbsp;"临时关联结果集" 进行条件过滤,删除不满足的行。</p>
<p>接下来我们搞两张测试表,一目了然。</p>
<pre class="language-sql highlighter-hljs"><code>-- 用户表(驱动表,左表)
CREATE TABLE `ysjz_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `ysjz_user` VALUES (1,'张三',18),(2,'李四',25),(3,'王五',30);

-- 订单表(被驱动表,右表)
CREATE TABLE `ysjz_order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`amount` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `ysjz_order` VALUES (1,1,100),(2,2,200),(3,2,300),(4,4,500); -- 注:user_id=4无对应用户</code></pre>
<p><strong>场景一:</strong>使用<strong>&nbsp;INNER JOIN</strong>,查询 年龄 &gt; 20 的用户及其订单。</p>
<p><strong>写法1:</strong>条件放 <strong>ON</strong> 后</p>
<pre class="language-sql highlighter-hljs"><code>SELECT u.*, o.*
FROM `ysjz_user` u
INNER JOIN `ysjz_order` o ON u.id = o.user_id AND u.age &gt; 20;</code></pre>
<p><img src="https://img2024.cnblogs.com/blog/1171560/202512/1171560-20251209220401310-1034297923.png" alt="场景一写法12"></p>
<p><strong>写法2:</strong>条件放 <strong>WHERE</strong> 后</p>
<pre class="language-sql highlighter-hljs"><code>SELECT u.*, o.*
FROM `ysjz_user` u
INNER JOIN `ysjz_order` o ON u.id = o.user_id
WHERE u.age &gt; 20;</code></pre>
<p><img src="https://img2024.cnblogs.com/blog/1171560/202512/1171560-20251209220401310-1034297923.png" alt="场景一写法12"></p>
<p>两种写法的 <strong>结果一致</strong>,<strong>效率也基本一致</strong>。</p>
<p><strong>场景二:</strong>使用 <strong>LEFT JOIN</strong>,<strong>保留所有用户</strong>,同时显示 年龄 &gt; 20 的用户及其订单(≤ 20 的用户订单显示为 NULL)。</p>
<p><strong>写法1:</strong>条件放 <strong>ON</strong> 后(符合要求)</p>
<pre class="language-sql highlighter-hljs"><code>SELECT u.*, o.*
FROM `ysjz_user` u
LEFT JOIN `ysjz_order` o ON u.id = o.user_id AND u.age &gt; 20;</code></pre>
<p><img src="https://img2024.cnblogs.com/blog/1171560/202512/1171560-20251209220457864-1184638392.png" alt="场景二写法1"></p>
<p><strong>写法2:</strong>条件放 <strong>WHERE</strong> 后(跟要求不符)</p>
<pre class="language-sql highlighter-hljs"><code>SELECT u.*, o.*
FROM `ysjz_user` u
LEFT JOIN `ysjz_order` o ON u.id = o.user_id
WHERE u.age &gt; 20;</code></pre>
<p><img src="https://img2024.cnblogs.com/blog/1171560/202512/1171560-20251209220521860-304789419.png" alt="场景二写法2"></p>
<p>写法2 将 张三 过滤了,并没有 保留所有用户。</p>
<p><strong>场景三:</strong>使用 <strong>LEFT JOIN</strong>,<strong>保留所有用户</strong>,同时显示 订单金额 &gt; 200&nbsp;的订单(无符合条件订单的用户填充为 NULL)。</p>
<p><strong>写法1:</strong>条件放 <strong>ON</strong> 后(符合要求)</p>
<pre class="language-sql highlighter-hljs"><code>SELECT u.*, o.*
FROM `ysjz_user` u
LEFT JOIN `ysjz_order` o ON u.id = o.user_id AND o.amount &gt; 200;</code></pre>
<p><img src="https://img2024.cnblogs.com/blog/1171560/202512/1171560-20251209220546156-1408082303.png" alt="场景三写法1"></p>
<p><strong>写法2:</strong>条件放 <strong>WHERE</strong> 后(跟要求不符)</p>
<pre class="language-sql highlighter-hljs"><code>SELECT u.*, o.*
FROM `ysjz_user` u
LEFT JOIN `ysjz_order` o ON u.id = o.user_id
WHERE o.amount &gt; 200;</code></pre>
<p><img src="https://img2024.cnblogs.com/blog/1171560/202512/1171560-20251209220608050-1181484514.png" alt="场景三写法2"></p>
<p>写法2 过滤了&nbsp;无符合条件订单的用户。</p>
<p>场景二 和 场景三 其实相差不大,只是条件作用的表不一样。</p>
<p><strong>ON</strong> 后面优先放 "表之间的关联键"(如 u.id = o.user_id),非关联的筛选条件(如 u.age &gt; 20)是否放 <strong>ON</strong> 后,取决于是否要保留驱动表的行。</p>
<p>总结:<strong>ON 管关联,WHERE 管过滤;LEFT JOIN 用 ON 保行,INNER JOIN 放哪都行看习惯。</strong></p>
<p style="text-align: right"><span style="color: rgba(53, 152, 219, 1)">别人的嘴你堵不住,但自己的心却任由自己掌控。-- 烟沙九洲</span></p>
<p><span data-cke-copybin-end="1">​</span></p><br><br>
来源:https://www.cnblogs.com/yanshajiuzhou/p/19328559
頁: [1]
查看完整版本: MySQL 筛选条件放 ON 后 vs 放 WHERE 后