Eu tenho uma tabela (no PostgreSQL 9.4) que se parece com isso:
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');
Agora, quero calcular para as datas especificadas e para todo tipo, em quantas linhas de dates_ranges
cada data caem. Zeros podem ser omitidos.
Resultado desejado:
+-------+------------+----+
| 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 |
+-------+------------+----+
Eu vim com duas soluções, uma com LEFT JOIN
eGROUP 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
e um com LATERAL
, que é um pouco mais 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
Gostaria de saber se existe alguma maneira melhor de escrever esta consulta? E como incluir pares do tipo data com contagem de 0?
Na realidade, existem alguns tipos distintos, período de até cinco anos (1800 datas) e ~ 30k linhas na dates_ranges
tabela (mas pode crescer significativamente).
Não há índices. Para ser preciso, no meu caso, é resultado da subconsulta, mas eu queria limitar a pergunta a um problema, por isso é mais geral.
2018-01-31
ou 2018-01-30
ou 2018-01-29
em que quando a primeira faixa tem todos eles?
generate_series
são parâmetros externos - eles não cobrem necessariamente todos os intervalos da dates_ranges
tabela. Quanto à primeira pergunta, suponho que não entendi - as linhas dates_ranges
são independentes, não quero determinar a sobreposição.
(1,2018-01-01,2018-01-15)
e(1,2018-01-20,2018-01-25)
deseja levar isso em consideração ao determinar quantas datas sobrepostas você tem?