I am trying to generate using generate_series()
for each day and each category, the count, in a given date range.
Table Posts
:
id | date | category_id |
---|---|---|
1 | 2022-01-01 | 1 |
2 | 2022-01-01 | 1 |
3 | 2022-01-02 | 1 |
4 | 2022-01-02 | 2 |
Table Categories
:
id | code |
---|---|
1 | WEB |
2 | MOBILE |
3 | DESKTOP |
Expected Results
:
day | code | count |
---|---|---|
2022-01-01 | WEB | 2 |
2022-01-01 | MOBILE | 0 |
2022-01-01 | DESKTOP | 0 |
2022-01-02 | WEB | 1 |
2022-01-02 | MOBILE | 1 |
2022-01-02 | DESKTOP | 0 |
2022-01-03 | WEB | 0 |
2022-01-03 | MOBILE | 0 |
2022-01-03 | DESKTOP | 0 |
2022-01-04 | WEB | 0 |
2022-01-04 | MOBILE | 0 |
2022-01-04 | DESKTOP | 0 |
2022-01-05 | WEB | 0 |
2022-01-05 | MOBILE | 0 |
2022-01-05 | DESKTOP | 0 |
So far I have :
SELECT day::date, code, count(p.id)
FROM generate_series('2022-01-01'::date, '2022-01-05'::date, '1 DAY') AS day
CROSS JOIN categories c
LEFT JOIN posts p ON p.category_id = c.id
WHERE date BETWEEN '2022-01-01' AND '2022-01-05'
GROUP BY (day, code)
ORDER BY day;
The results is not quite there, I have some intuition that I should join on a sub-query but I'm not sure.
Thanks for your help.
CodePudding user response:
You can first find the counts for each category per day, and then join the results onto the series:
select d::date, c.code, coalesce(t.c, 0)
from generate_series('2022-01-01'::date, '2022-01-05'::date, '1 day') d
cross join categories c
left join (select p.date, p.category_id, count(*) c
from posts p group by p.date, p.category_id) t
on c.id = t.category_id and t.date = d::date