Для Postgres это можно сделать с помощью generate_series()
, чтобы сгенерировать список дат для каждого идентификатора пользователя и использования в левом соединении:
with workingtime (userid, regday, checkin, checkout) as(
values
(1, date '2019-04-03', '08:48'::time, '18:00'::time),
(1, date '2019-04-05', '08:00'::time, '18:00'::time),
(1, date '2019-04-06', '07:48'::time, '18:00'::time),
(1, date '2019-04-09', '08:20'::time, '18:00'::time),
(1, date '2019-04-10', '08:00'::time, '18:00'::time),
(2, date '2019-04-03', '08:48'::time, '18:00'::time),
(2, date '2019-04-06', '07:00'::time, '18:00'::time),
(2, date '2019-04-08', '07:48'::time, '18:00'::time),
(2, date '2019-04-09', '08:20'::time, '18:00'::time)
), ranges as (
select w.userid, dt.day::date as regdate
from (
select distinct userid
from workingtime
) w
cross join generate_series(date '2019-04-03', date '2019-04-11', interval '1 day') as dt(day)
)
select r.userid,
count(*) filter (where checkin < '08:00') as total_late,
count(*) filter (where wt.regday is null) as total_days_off
from ranges r
left join workingtime wt on wt.userid = r.userid and wt.regday = r.regdate
group by r.userid
order by r.userid;
Вышеуказанное возвращает:
userid | total_late | total_days_off
-------+------------+---------------
1 | 1 | 4
2 | 2 | 5