-1

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

**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
..

表 Email 中的所有值都匹配,即所有电子邮件和带有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 中具有行的电子邮件。
我究竟做错了什么?

4

2 回答 2

1

要在处理连接时将主表中的不匹配行保留在循环中(只是 的倒数,您需要将相应的条件放入子句而不是子句中:OUTERLEFTRIGHTJOINWHERE

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 NULL或添加到每个相应的条件来解决问题WHERE,但这通常更慢且不太优雅。

旁白

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

count(m.recipient)可能比count(m.id). 如果mail.id不应该定义NOT NULL,可能会导致意想不到的结果。mail.recipient不能NULL用于此查询中定义的匹配行。

于 2013-11-04T17:39:28.820 回答
1

如果您按过去一小时内到达的消息进行过滤,您只会得到拥有其中一条消息的人。

也检查空值。

WHERE m.time IS NULL OR m.time > current_timstamp...
于 2013-11-04T15:39:43.627 回答