这是我数据库中表格的结构:
**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中有行的电子邮件。
我做错了什么?
答案 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 NULL
或WHERE
子句中的每个条件来解决问题,但这通常会更慢,更不优雅。
不要将time
用作列名。它在Postgres中是允许的,但它是SQL标准中的基本类型名称和保留字。可能导致混淆错误和错误消息。
count(m.recipient)
可能比count(m.id)
更安全/更快。如果不应定义mail.id
NOT NULL
,则可能会导致意外结果。根据此查询中的定义,mail.recipient
对于匹配的行不能为NULL
。