J'ai une table (dans PostgreSQL 9.4) qui ressemble à ceci:
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');
Maintenant, je veux calculer pour les dates données et pour chaque type, dans combien de lignes de dates_ranges
chaque date tombe. Des zéros pourraient éventuellement être omis.
Résultat désiré:
+-------+------------+----+
| 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 |
+-------+------------+----+
J'ai trouvé deux solutions, une avec LEFT JOIN
etGROUP 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
et un avec LATERAL
, qui est légèrement plus rapide:
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
Je me demande si c'est une meilleure façon d'écrire cette requête? Et comment inclure des paires date-kind avec 0 compte?
En réalité, il existe plusieurs types distincts, une période pouvant aller jusqu'à cinq ans (1800 dates) et environ 30 000 lignes dans le dates_ranges
tableau (mais cela pourrait augmenter considérablement).
Il n'y a pas d'index. Pour être précis dans mon cas, c'est le résultat d'une sous-requête, mais j'ai voulu limiter la question à un seul problème, c'est donc plus général.
2018-01-31
ou 2018-01-30
ou 2018-01-29
en quand la première gamme a tous?
generate_series
sont des paramètres externes - elles ne couvrent pas nécessairement toutes les plages du dates_ranges
tableau. Quant à la première question, je suppose que je ne la comprends pas - les lignes dates_ranges
sont indépendantes, je ne veux pas déterminer les chevauchements.
(1,2018-01-01,2018-01-15)
et(1,2018-01-20,2018-01-25)
voulez-vous en tenir compte lorsque vous déterminez le nombre de dates qui se chevauchent?