To also see missing rows in the result, left join to a complete grid of possible rows. The grid is built from all possible combinations of (req_time, customer_id, req_status)
with cross joins:
SELECT d.req_time, c.customer_id, s.req_status, count(t.req_time) AS ct
FROM (
SELECT generate_series (min(req_time), max(req_time), '1 day')::date
FROM tbl
) d(req_time)
CROSS JOIN (SELECT DISTINCT customer_id FROM tbl) c(customer_id)
CROSS JOIN (VALUES ('FAILED'::text), ('OK')) s(req_status)
LEFT JOIN tbl t USING (req_time, customer_id, req_status)
GROUP BY 1,2,3
ORDER BY 1,2,3;
Count on a column from the actual table, which will be 0 if no match is found (NULL values don't count).
Assuming req_time
to be a date
(not timestamp
).
Similar answer here:
array_agg group by and null