sql group by date给出了错误的结果

时间:2017-08-08 09:11:05

标签: sql postgresql

我真的不知道如何命名一个话题,请原谅我:c 我想从数据库中获取一些统计信息。我有3张桌子,就像这样:

Sent messages: 
id(send_id)
stamp(timestmap)

Replies:
id
send_id
stamp(timestamp)

Opened:
id
send_id
stamp

问题是在打开的表中我保存每个用户邮件打开的标记。因此,如果用户打开我的电子邮件3次,则有3封邮件:

id      [1, 2, 3]                                        
send_id [1, 1, 1]                      
stamp   [2017-08-06 15:15:12, 2017-08-07 12:11:12, 2017-08-08 20:15:05]  

现在,我希望每天都有统计数据,如下所示:

sent  opened replied date
50    35     10      2017-08-01
20    15     5       2017-08-02
125   80     20      2017-08-03

这是我的问题,这是否可以检查前一行中是否已存在特定的send_id,并跳过计数,因为现在,如果用户在3天不同的时间打开电子邮件,那么我每天都有+1,但是它应该只在他打开它的第一天加1。

我当前的选择:

select COUNT(DISTINCT s.id) as "sent",
       COUNT(DISTINCT CASE WHEN o.send_id is NULL THEN NULL ELSE s.id END) as "opened",
       COUNT(DISTINCT CASE WHEN r.send_id is NULL THEN NULL ELSE s.id END) as "replied",      
       o.stamp::timestamp::date as date
from db_send s
left join db_reply r ON(r.send_id = s.id)
left join db_send_open o ON (o.send_id = s.id)

group by date
order by date

所以问题是:我有更多的已打开邮件,因为我不知道如何仅通过send_id对它们进行分组(不是按日期,但我也必须按日期分组:ccc,所以利益冲突并选择一个日期最短的

2 个答案:

答案 0 :(得分:1)

你可以在CTE中预先打开数据,如:

with db_send_open as (
select min(stamp) stamp, send_id
from db_send_open
group by send_id
)
select COUNT(DISTINCT s.id) as "sent",
       count (o.send_id) as "opened",
       COUNT(DISTINCT CASE WHEN r.send_id is NULL THEN NULL ELSE s.id END) as "replied",      
       o.stamp::timestamp::date as date
from db_send s
left join db_reply r ON(r.send_id = s.id)
left join db_send_open o ON (o.send_id = s.id)

group by date
order by date

答案 1 :(得分:1)

以下是可以解决您的问题的查询。它与Vao提供的几乎相同。但是CTE通常在运行时占用数据库中的内存空间,因为CTE可以在查询脚本中多次使用。仅当重用相同的结果集时,建议才使用CTE。由于这是一个邮件系统,我认为你处理的记录非常高,因此CTE可能会降低你的表现。

如果永远不打开邮件,我也假设将sendtime作为opendate。如果不需要,您可以删除案例陈述。

select case when b.opendate is null then date(a.senttime) else b.opendate 
end opendate,count(a.id) mail_sent,count(b.send_id) "read",count(distinct 
c.send_id) replied
from waggle.sent_kn a
left join 
(select send_id,date(min(opentime)) opendate  from
waggle.opened_kn
group by send_id)b
on a.id=b.send_id
left join waggle.replied_kn c
on c.send_id = a.id
group by case when b.opendate is null then date(a.senttime) else b.opendate 
end;

希望这有帮助!! :)

相关问题