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决定留哪些。顺序不同,结果差很多。