Ich habe eine Tabelle (in PostgreSQL 9.4), die so aussieht:
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');
Jetzt möchte ich für die angegebenen Daten und für jede Art berechnen, in wie viele Zeilen von dates_ranges
jedem Datum fallen. Nullen könnten möglicherweise weggelassen werden.
Erwünschtes Ergebnis:
+-------+------------+----+
| 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 |
+-------+------------+----+
Ich habe zwei Lösungen gefunden, eine mit LEFT JOIN
undGROUP 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
und eins mit LATERAL
, was etwas schneller ist:
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
Ich frage mich, ob es eine bessere Möglichkeit ist, diese Abfrage zu schreiben. Und wie kann man Datumspaare mit 0 zählen?
In Wirklichkeit gibt es einige verschiedene Arten, einen Zeitraum von bis zu fünf Jahren (1800 Daten) und ~ 30.000 Zeilen in der dates_ranges
Tabelle (aber es könnte erheblich wachsen).
Es gibt keine Indizes. In meinem Fall ist es ein Ergebnis einer Unterabfrage, aber ich wollte die Frage auf ein Problem beschränken, damit es allgemeiner ist.
2018-01-31
oder 2018-01-30
oder 2018-01-29
drin, wenn der erste Bereich alle hat?
generate_series
sind externe Parameter - sie decken nicht unbedingt alle Bereiche in der dates_ranges
Tabelle ab. Was die erste Frage dates_ranges
betrifft, verstehe ich sie vermutlich nicht - Zeilen in sind unabhängig, ich möchte keine Überlappung feststellen.
(1,2018-01-01,2018-01-15)
und(1,2018-01-20,2018-01-25)
möchten Sie dies berücksichtigen, wenn Sie bestimmen, wie viele überlappende Daten Sie haben?