Reputation: 130
My schema is:
create table calendar(day date);
insert into calendar values('2020-09-01'), ('2020-09-02'), ('2020-09-03');
create table messages(id integer primary key auto_increment, user_id integer, created_at date);
insert into messages(user_id, created_at) values(1, '2020-09-01'), (1, '2020-09-01'), (2, '2020-09-01'), (2, '2020-09-03')
I need to get count of messages for every user for every date in range:
|user_id|data |
|1 |2,0,0|
|2 |1,0,1|
my query is:
SELECT r.user_id, group_concat(r.cnt ORDER BY r.day) AS data
FROM
(SELECT calendar.day, user_id, count(messages.id) cnt
FROM calendar LEFT JOIN messages ON date(messages.created_at) = calendar.day
WHERE calendar.day BETWEEN '2020-09-01' AND '2020-09-03'
GROUP BY user_id, date_format(calendar.day, '%Y-%m-%d')) r
GROUP BY r.user_id;
what I exactly get:
|user_id|data |
|NULL |0 |
|1 |2 |
|2 |1,1 |
I don't know how to group it right, please help me. SQL Fiddle
Upvotes: 1
Views: 47
Reputation: 222722
You can cross join
the list of distinct users with the calendar to generate all possible combinations, then bring the table with a left join
.
The rest is just aggregation logic, which you already have in place:
select user_id, group_concat(cnt order by day) data
from (
select u.user_id, c.day, count(m.id) cnt
from calendar c
cross join (select distinct user_id from messages) u
left join messages m
on m.created_at >= c.day and m.created_at < c.day + interval 1 day
and m.user_id = u.user_id
where c.day between '2020-09-01' and '2020-09-03'
group by u.user_id, c.day
) t
group by user_id
In a real life situation, you would probably have a separate table to store the users, that you can directly use instead of selecting the distinct values from the messages table.
user_id | data ------: | :---- 1 | 2,0,0 2 | 1,0,1
Upvotes: 1