Mam tabelę (w PostgreSQL 9.4), która wygląda następująco:
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');
Teraz chcę obliczyć dla podanych dat i dla każdego rodzaju, ile wierszy z dates_ranges
każdej daty przypada. Zera można ewentualnie pominąć.
Pożądany rezultat:
+-------+------------+----+
| 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 |
+-------+------------+----+
Wymyśliłem dwa rozwiązania, jedno z LEFT JOIN
iGROUP 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
i jeden z LATERAL
, który jest nieco szybszy:
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
Zastanawiam się, czy jest lepszy sposób na napisanie tego zapytania? A jak uwzględnić pary dat z liczbą 0?
W rzeczywistości istnieje kilka różnych rodzajów, okres do pięciu lat (1800 dat) i ~ 30 000 wierszy w dates_ranges
tabeli (ale może znacznie wzrosnąć).
Brak indeksów. Mówiąc dokładniej, w moim przypadku jest to wynikiem podzapytania, ale chciałem ograniczyć pytanie do jednego problemu, więc jest bardziej ogólne.
2018-01-31
lub 2018-01-30
czy 2018-01-29
w tym, kiedy pierwszy zakres ma wszystkie z nich?
generate_series
są parametrami zewnętrznymi - niekoniecznie obejmują wszystkie zakresy w dates_ranges
tabeli. Co do pierwszego pytania, to chyba nie rozumiem - wiersze dates_ranges
są niezależne, nie chcę określać nakładania się.
(1,2018-01-01,2018-01-15)
i(1,2018-01-20,2018-01-25)
czy chcesz wziąć to pod uwagę przy określaniu liczby pokrywających się dat?