问题描述
|
有人可以帮我理解将WHERE子句添加到具有COUNT(*)的LEFT JOIN的查询时发生的以下行为吗?
我有两个表:
TABLE 1: customers
customer_id | name
------------------
1 | Bob
2 | James
3 | Fred
TABLE 2: orders
order_id | customer_id | order_timestamp
----------------------------------------
1000 | 1 | 2011-01-01 00:00
1001 | 1 | 2011-01-05 00:00
1002 | 2 | 2011-01-10 00:00
现在,以下查询告诉我每个客户下了多少个订单:
select c.customer_id,count(o.order_id)
from customers c
left join orders o using (customer_id)
group by 1
customer_id | count
-------------------
1 | 2
2 | 1
3 | 0
如果我在查询中添加WHERE子句,则效果很好,但是即使我正在执行LEFT JOIN,对于没有下订单的客户,查询也不再输出零计数:
select c.customer_id,count(o.order_id)
from customers c
left join orders o using (customer_id)
where o.order_timestamp >= \'2011-01-05\'
group by 1
customer_id | count
-------------------
1 | 1
2 | 1
现在,如果像下面那样将WHERE条件作为LEFT JOIN的一部分移动,我将为未下订单的客户取回我的零计数:
select c.customer_id,count(o.order_id)
from customers c
left join orders o on (c.customer_id = o.customer_id) and (o.order_timestamp >= \'2011-01-05\')
group by 1
我很困惑为什么第二个查询不起作用,而第三个查询却起作用?有人可以给我一个解释吗?也不确定这是否重要,但是我正在使用postgres。谢谢!
解决方法
这是因为NULL不大于等于。如果将WHERE子句更改为
where o.order_timestamp is null or o.order_timestamp >= \'2011-01-05\'
,则将获得与join子句限制相同的行为。
但是请注意-我建议使用join子句方法,因为它与您要执行的操作更加匹配。同样,仅当order_timestamp列不可为空时,我上面提到的WHERE子句的更改也将起作用-如果为空,则应使用其他列进行空检查(例如eg5ѭ)。
, 在处理外部联接(右,左)时,过滤条件的位置很重要。在JOIN之前应用OUTER JOIN的ON子句中的条件;在JOIN之后应用WHERE子句中的条件-对使用JOIN的结果集应用。
SELECT c.customer_id,COUNT(o.order_id)
FROM CUSTOMERS c
LEFT JOIN ORDERS o ON o.customer_id - c.customer_id
AND o.order_timestamp >= \'2011-01-05\'
GROUP BY c.customer_id
普通人
建议不要使用序号,即使用一个数字值来引用SELECT子句中列的数字位置。如果有人更改了查询(例如添加一列),则可能会严重影响您的查询。
, Chirs是正确的,null不大于或等于任何值。因此,当您将条件包含在where子句中时,它适用于左连接生成的结果的最终视图(表),
在这种情况下,您的条件将删除时间戳为null的行。
但是,当您在进行联接时应用相同条件时,该条件仅适用于订单表,而不适用于左联接。因此,它不会删除时间戳为null的行。
因此,在生成最终表之前应用的第三查询条件中以及在生成最终表之后应用的第二查询条件中