2015-03-31 26 views
2

比方说,我有这样的一个这样的搜索查询:获取创建的条目的数量每天

SELECT COUNT(id), date(created_at) 
FROM entries 
WHERE date(created_at) >= date(current_date - interval '1 week') 
GROUP BY date(created_at) 

如你所知然后例如我得到的结果类似下面:

count | date 
    2 | 15.01.2014 
    1 | 13.01.2014 
    9 | 09.01.2014 

但我做了而不是得到了一周中没有创建条目的日子。

我怎样才能得到一个看起来像这样的搜索结果,包括那里没有创建条目的日子?

count | date 
    2 | 15.01.2014 
    0 | 14.01.2014 
    1 | 13.01.2014 
    0 | 12.01.2014 
    0 | 11.01.2014 
    0 | 10.01.2014 
    9 | 09.01.2014 

回答

2
SELECT day, COALESCE(ct, 0) AS ct 
FROM (SELECT now::date - d AS day FROM generate_series (0, 6) d) d -- 6, not 7 
LEFT JOIN (
    SELECT created_at::date AS day, count(*) AS ct 
    FROM entries 
    WHERE created_at >= date_trunc('day', now()) - interval '6d' 
    GROUP BY 1 
    ) e USING (day); 
  • 使用sargable表达你的WHERE条件,所以Postgres对使用普通指数created_at。对于性能而言,远比其他所有方面都重要。

  • 为了掩盖一个星期(包括今天),减去6天从“今天”开始,而不是7

  • 假设id定义NOT NULLcount(*)是相同的count(id)这里,但稍快。

  • A CTE会在这里矫枉过正。它更慢更冗长。

  • 先汇总,稍后加入。在这种情况下速度更快。

  • now()是标准SQL CURRENT_TIMESTAMP(您可以使用它)的稍短且更快的Postgres实现。

这应该是最短和最快的查询。用EXPLAIN ANALYZE进行测试。

相关:

+0

感谢您的回答!如果它起作用,我会将它标记为正确的,但是目前我得到一个错误:FEHLER:Unfranfrage FROM FROM muss Aliasnamen erhalten ZEILE 2:FROM(SELECT now :: date - d AS day FROM generate_series(0,... – 2015-03-31 08:26:52

+0

Dou you我知道我该如何解决这个问题! – 2015-03-31 09:11:17

+0

我使用'当前日期'修复了它,并给出了一个别名!谢谢 – 2015-03-31 09:17:37

2

做这个尝试此查询:

with a as (select current_date - n as dt from generate_series(0, 6) as t(n)), 
    b as (select count(id) cnt, date(created_at) created_at 
      from entries 
      where date(created_at) >= date(current_date - interval '1 week') 
      group by date(created_at)) 
select coalesce(b.cnt,0), a.dt 
from a 
left join b on (a.dt = b.created_at) 
order by a.dt; 

count功能不会为不存在的行产生0。所以你必须填写缺失日期的行。使用generate_series和简单的日期算术,您可以生成某个时间段(本例中为1周)的日期行。然后你可以外连接来产生最终结果。​​3210将替代null0

+0

作品!但是有没有更短的? – 2015-03-31 07:24:29

+0

您可以放弃COALESCE(),COUNT(列)不计数NULL值。 COUNT(*)计数记录并且不检查NULL。 – 2015-03-31 07:33:27

-1

使用generate_series()创建你所需要的日期,并加入到日期的这个名单:

SELECT COUNT(id), 
    date(gdate) 
FROM entries 
    RIGHT JOIN generate_series(current_date - interval '1 week', current_date, '1 day') g(gdate) 
    ON date(created_at) = date(gdate) AND date(created_at) >= date(current_date - interval '1 week') 
GROUP BY 
    date(gdate) 
ORDER BY 
    date(gdate) DESC; 
+0

对不起,但似乎不工作! – 2015-03-31 07:23:26

+0

@JohnSmith:你会得到什么样的错误/问题?它一定是这样的,但我没有测试它。 – 2015-03-31 07:30:23

+0

我得到和以前一样的结果! – 2015-03-31 07:36:19

相关问题