【问题标题】:Getting zero-values from a right joined table从右连接表中获取零值
【发布时间】:2013-11-15 05:59:32
【问题描述】:

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

**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 表中具有行的电子邮件。
我做错了什么?

【问题讨论】:

    标签: sql postgresql count outer-join


    【解决方案1】:

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

    也检查 null。

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

    【讨论】:

      【解决方案2】:

      要在处理OUTER joins (LEFT is just the inverse of RIGHT) 时将 表中不匹配的行保留在循环中,您需要将相应的条件放入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 子句中添加条件,则 result 必须匹配( 连接表之后) - 否则整行将从输出中丢弃。

      可以通过将OR col IS NULL 或添加到WHERE 子句中的每个条件来解决问题,但这通常更慢且不太优雅。

      旁白

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

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

      【讨论】:

        猜你喜欢
        • 2021-04-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-28
        • 1970-01-01
        • 2021-06-14
        相关资源
        最近更新 更多