缺少具有左连接和count()的行所需的说明

时间:2011-06-04 04:51:39

标签: sql postgresql aggregate-functions

有人可以帮我理解当我将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。谢谢!

3 个答案:

答案 0 :(得分:6)

这是因为NULL不大于或等于任何东西;如果将WHERE子句更改为where o.order_timestamp is null or o.order_timestamp >= '2011-01-05',那么您将获得与join子句限制相同的行为。

请注意 - 我会建议使用join子句方法,因为它与您尝试的方法更紧密地匹配。此外,上面提到的WHERE子句的更改仅在order_timestamp列不可为空时才有效 - 如果是,则应使用不同的列进行空检查(例如,where o.primarykey is null or o.order_timestamp >= '2011-01-05')。

答案 1 :(得分:5)

在处理OUTER连接(RIGHT,LEFT)时,过滤条件的放置很重要。在JOIN之前应用OUTER JOIN的ON子句中的标准; WHERE子句中的条件在 JOIN之后应用 - 应用于使用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子句中列的数字位置的数值的常数,不建议使用。如果有人更改了查询 - 例如添加列 - 则可能会严重影响您的查询。

答案 2 :(得分:0)

Chirs是对的,null不大于或等于任何东西。因此,当您在where子句中包含条件时,它应用于左连接生成的结果的最终视图(表), 在此结果中,您的条件将删除时间戳为null的行。

但是,在执行连接时应用相同条件时,条件仅适用于订单表,而不是执行左连接。因此它不会删除时间戳为null的行。

因此,在最终表生成之前应用的第三个查询条件和在最终表生成之后应用的第二个查询条件