从右连接表中获取零值

时间:2013-11-04 15:09:57

标签: sql postgresql count outer-join

这是我数据库中表格的结构:

**Email**
id (PK)
email

**Mail**
id (PK)
recipient
time
...

为了获得特定电子邮件收到的邮件的分发,我执行以下查询:

select e.email,count(m.id) from mail m 
    right outer join email e on m.recipient=e.email
    group by e.email

我明白了:

"e1";0
"e2";3644
"e3";0
"e4";10
"e5";4620
..

表格电子邮件中的所有值都匹配,即所有电子邮件和count=0的电子邮件。没关系。

问题是当我按日期过滤结果时:

select e.email,count(m.id) from mail m 
right outer join email e on m.recipient=e.email
where m.time >= current_timestamp - interval '1 hour'
group by e.email

结果是:

"e1";1
"e2";1
"e3";1
...

我没有得到count=0的值,我只是收到表Mail中有行的电子邮件。
我做错了什么?

2 个答案:

答案 0 :(得分:1)

如果按过去一小时内到达的邮件进行过滤,则只会收到包含其中一封邮件的人。

检查是否为空。

WHERE m.time IS NULL OR m.time > current_timstamp...

答案 1 :(得分:1)

要在处理OUTER joins (LEFT is just the inverse of RIGHT)时保持循环中 main 表中不匹配的行,您需要将相应的条件放入 JOIN子句而不是WHERE子句:

SELECT e.email, count(m.id)
FROM   email e
LEFT   JOIN mail m ON m.recipient = e.email
                  AND m.time >= now() - interval '1 hour'
GROUP  BY 1;

这样,mail中的行只有在与连接条件匹配时才会被追加 - 否则后面的列默认为NULL(但仍会返回该行)。

如果在WHERE子句中添加条件,则结果必须匹配(连接表之后) - 否则整行将从输出中丢弃

可以通过添加OR col IS NULLWHERE子句中的每个条件来解决问题,但这通常会更慢,更不优雅。

旁白

不要将time用作列名。它在Postgres中是允许的,但它是SQL标准中的基本类型名称和保留字。可能导致混淆错误和错误消息。

count(m.recipient)可能比count(m.id)更安全/更快。如果不应定义mail.id NOT NULL,则可能会导致意外结果。根据此查询中的定义,mail.recipient对于匹配的行不能为NULL