Tengo una tabla (en PostgreSQL 9.4) que se ve así:
CREATE TABLE dates_ranges (kind int, start_date date, end_date date);
INSERT INTO dates_ranges VALUES
(1, '2018-01-01', '2018-01-31'),
(1, '2018-01-01', '2018-01-05'),
(1, '2018-01-03', '2018-01-06'),
(2, '2018-01-01', '2018-01-01'),
(2, '2018-01-01', '2018-01-02'),
(3, '2018-01-02', '2018-01-08'),
(3, '2018-01-05', '2018-01-10');
Ahora quiero calcular para las fechas dadas y para cada tipo, en cuántas filas de dates_ranges
cada fecha cae. Los ceros podrían posiblemente omitirse.
Resultado deseado:
+-------+------------+----+
| kind | as_of_date | n |
+-------+------------+----+
| 1 | 2018-01-01 | 2 |
| 1 | 2018-01-02 | 2 |
| 1 | 2018-01-03 | 3 |
| 2 | 2018-01-01 | 2 |
| 2 | 2018-01-02 | 1 |
| 3 | 2018-01-02 | 1 |
| 3 | 2018-01-03 | 1 |
+-------+------------+----+
Se me ocurrieron dos soluciones, una con LEFT JOIN
yGROUP BY
SELECT
kind, as_of_date, COUNT(*) n
FROM
(SELECT d::date AS as_of_date FROM generate_series('2018-01-01'::timestamp, '2018-01-03'::timestamp, '1 day') d) dates
LEFT JOIN
dates_ranges ON dates.as_of_date BETWEEN start_date AND end_date
GROUP BY 1,2 ORDER BY 1,2
y uno con LATERAL
, que es un poco más rápido:
SELECT
kind, as_of_date, n
FROM
(SELECT d::date AS as_of_date FROM generate_series('2018-01-01'::timestamp, '2018-01-03'::timestamp, '1 day') d) dates,
LATERAL
(SELECT kind, COUNT(*) AS n FROM dates_ranges WHERE dates.as_of_date BETWEEN start_date AND end_date GROUP BY kind) ss
ORDER BY kind, as_of_date
Me pregunto si hay alguna forma mejor de escribir esta consulta. ¿Y cómo incluir pares date-kind con 0 count?
En realidad, hay algunos tipos distintos, un período de hasta cinco años (1800 fechas) y ~ 30k filas en la dates_ranges
tabla (pero podría crecer significativamente).
No hay índices Para ser precisos en mi caso, es el resultado de una subconsulta, pero he querido limitar la pregunta a un problema, por lo que es más general.
2018-01-31
o 2018-01-30
o 2018-01-29
en él cuando la primera gama cuenta con todos ellos?
generate_series
son parámetros externos; no necesariamente cubren todos los rangos de la dates_ranges
tabla. En cuanto a la primera pregunta, supongo que no la entiendo: las filas dates_ranges
son independientes, no quiero determinar la superposición.
(1,2018-01-01,2018-01-15)
y(1,2018-01-20,2018-01-25)
desea tenerlo en cuenta al determinar cuántas fechas superpuestas tiene?