Get count of created entries for each day

杀马特。学长 韩版系。学妹 提交于 2019-12-13 14:48:21

问题


Let's say I have a this search query like this:

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

As you know then for example I get a result back like this:

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

But I do not get the days of the week where no entries where created.

How can I get a search result that looks like this, including the days where no entries where created?

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

回答1:


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);
  • Use a sargable expression for your WHERE condition, so Postgres can use a plain index on created_at. Far more important for performance than all the rest.

  • To cover a week (including today), subtract 6 days from the start of "today", not 7.

  • Assuming that id is defined NOT NULL, count(*) is identical to count(id) here, but slightly faster.

  • A CTE would be overkill here. It's slower and more verbose.

  • Aggregate first, join later. That's faster in this case.

  • now() is the slightly shorter and faster Postgres implementation of the standard SQL CURRENT_TIMESTAMP (which you can use as well).

This should be the shortest and fastest query. Test with EXPLAIN ANALYZE.

Related:

  • Selecting sum and running balance for last 18 months with generate_series
  • PostgreSQL: running count of rows for a query 'by minute'



回答2:


Try this query:

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 function will not generate 0 for non-existing rows. So you have to fill the rows for missing dates. With generate_series and simple date arithmetic, you can generate rows for dates of some period (in this case, 1 week). Then you can outer join to generate the final result. coalesce will substitute null to 0.




回答3:


You need to tell SQL to handle NULL. Return 0 if NULL

You can do this by COALESCE

http://www.postgresql.org/docs/devel/static/functions-conditional.html




回答4:


Use generate_series() to create the dates you need and JOIN to this list of dates:

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;


来源:https://stackoverflow.com/questions/29362384/get-count-of-created-entries-for-each-day

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!