数码工坊
白蓝主题五 · 清爽阅读
首页  > 表格技巧

SQL查询中ON和WHERE的区别,别再搞混了

ref="/tag/143/" style="color:#2B406D;font-weight:bold;">SQL查询中ON和WHERE的区别,别再搞混了

写SQL的时候,很多人用JOIN连表,然后顺手把过滤条件全扔到WHERE里,结果数据不对还不知道哪儿出问题。其实关键就在ON和WHERE的区别上,搞清楚这个,查起表来才不踩坑。

ON是在连接时过滤

ON是定义两张表怎么关联的条件。它在生成临时结果集的时候就起作用,决定了哪些行能被连进来。哪怕某条记录在另一张表里没匹配上,根据JOIN类型,也可能保留主表的数据。

比如你查订单和用户信息,想看看每个订单对应的用户名:

SELECT o.order_id, u.user_name 
FROM orders o 
LEFT JOIN users u ON o.user_id = u.id

这里的ON确保只有user_id和id匹配的记录才会关联上。如果是LEFT JOIN,就算用户被删了,订单照样显示,只是用户名为空。

WHERE是连接完再筛选

WHERE是在表连完之后,对最终结果再做一次过滤。它不会影响连接过程,只管最后呈现哪些数据。

继续上面的例子,如果你加个WHERE条件:

SELECT o.order_id, u.user_name 
FROM orders o 
LEFT JOIN users u ON o.user_id = u.id 
WHERE u.user_name = '张三'

这时候虽然用了LEFT JOIN,但WHERE要求用户名必须是‘张三’,那其他用户或者用户为空的订单全都被筛掉了,相当于变相变成了INNER JOIN的效果。

实际场景中的坑

假设你做报表,要统计每个部门的员工数,包括没人去的空部门。你这么写:

SELECT d.name, COUNT(e.id) as emp_count 
FROM departments d 
LEFT JOIN employees e ON d.id = e.dept_id 
WHERE e.status = '在职' 
GROUP BY d.name

结果发现,有些部门明明有人,但数量为零,甚至空部门也消失了。问题就出在WHERE上。status='在职'这个条件会把非在职或为空的记录过滤掉,连带着部门也被排除。

正确做法是把状态判断移到ON里:

SELECT d.name, COUNT(e.id) as emp_count 
FROM departments d 
LEFT JOIN employees e ON d.id = e.dept_id AND e.status = '在职' 
GROUP BY d.name

这样连接时只关联“在职”员工,但部门依然全部保留,统计才准确。

简单说:ON决定怎么连,WHERE决定留哪些。顺序不同,结果差很多。