This script gives the hourly count of the timestamps in the table.
SELECT date_trunc('hour', s.fill_instant) h , count(date_trunc('hour', s.fill_instant)) c FROM sms s
left join station s2 on
s.station_id = s2.station_id
where
s2.address like '%arizona%' and s.fill_date between '2021-09-19' and '2021-09-19'
GROUP BY date_trunc('hour', s.fill_instant)
order by date_trunc('hour', s.fill_instant) asc;
in the table like the following
2021-09-19 00:00:00 3
2021-09-19 02:00:00 20
2021-09-19 03:00:00 6
2021-09-19 13:00:00 7
2021-09-19 14:00:00 11
2021-09-19 15:00:00 6
How can I insert the Zeros in the non present hours. so it shows the map of complete 24 hours. much like this
2021-09-19 00:00:00 3
2021-09-19 01:00:00 0
2021-09-19 02:00:00 20
2021-09-19 03:00:00 6
2021-09-19 04:00:00 0
2021-09-19 05:00:00 0
2021-09-19 06:00:00 0
2021-09-19 07:00:00 0
2021-09-19 08:00:00 0
2021-09-19 09:00:00 0
2021-09-19 10:00:00 0
2021-09-19 11:00:00 0
2021-09-19 12:00:00 0
2021-09-19 13:00:00 7
2021-09-19 14:00:00 11
2021-09-19 15:00:00 6
2021-09-19 16:00:00 0
2021-09-19 17:00:00 0
2021-09-19 18:00:00 0
2021-09-19 19:00:00 0
2021-09-19 20:00:00 0
2021-09-19 21:00:00 0
2021-09-19 22:00:00 0
2021-09-19 23:00:00 0
2021-09-19 24:00:00 0
CodePudding user response:
Use generate_series
to get all hours for the given day as a CTE then left join
it with your query:
WITH hours as (Select * from generate_series('2021-09-19 00:00:00'::timestamp, '2021-09-19 23:59:59'::timestamp, INTERVAL '1 hour') as hr)
SELECT hours.hr, coalesce(qry.c, 0) as c
FROM hours
LEFT JOIN(SELECT date_trunc('hour', s.fill_instant) h , count(date_trunc('hour', s.fill_instant)) c FROM sms s
left join station s2 on s.station_id = s2.station_id
where
s2.address like '%arizona%' and s.fill_date between '2021-09-19' and '2021-09-19'
GROUP BY date_trunc('hour', s.fill_instant)
order by date_trunc('hour', s.fill_instant) asc) qry on qry.h = hours.hr
CodePudding user response:
A more or less generic pattern for filling gaps in a sequence would be this:
Use your existing query (t
) and outer join it with the dense sequence of hours (ds
). Use coalesce
to set null
values of t.c
as 0.
with t as
(
.. your query here ..
)
select ds.h, coalesce(t.c, 0) c
from generate_series
(
timestamp '2021-09-19T00:00:00',
timestamp '2021-09-19T24:00:00',
interval '1 hour'
) as ds(h)
left outer join t on t.h = ds.h;
CodePudding user response:
Another way to generate all hours of a day is use a recursive query.
Then you have to make a LEFT JOIN
between hours
subquery and your query, and in those rows that do not match your query (c
column is null), you have to put a zero (I used a CASE
statement).
WITH RECURSIVE hours AS (SELECT '2021-09-19 00:00:00'::timestamp AS hour
UNION ALL
SELECT hour interval '1 hour'
FROM hours
WHERE hour < '2021-09-19 23:00:00')
SELECT hours.hour, CASE WHEN sq.c IS NULL THEN 0 ELSE sq.c END AS c
FROM hours
LEFT JOIN (SELECT date_trunc('hour', s.fill_instant) h, count(date_trunc('hour', s.fill_instant)) c
FROM sms s
LEFT JOIN station s2 ON s.station_id = s2.station_id
WHERE s2.address like '%arizona%' AND s.fill_date = '2021-09-19'
GROUP BY date_trunc('hour', s.fill_instant)) AS sq ON hours.hour = sq.h
ORDER BY hours.hour;