Ich habe eine Abfrage wie diese, die eine Reihe von Daten zwischen zwei angegebenen Daten generiert:
select date '2004-03-07' + j - i as AllDate
from generate_series(0, extract(doy from date '2004-03-07')::int - 1) as i,
generate_series(0, extract(doy from date '2004-08-16')::int - 1) as j
Es generiert 162 Daten zwischen 2004-03-07
und 2004-08-16
und dem, was ich will. Das Problem mit diesem Code ist, dass er nicht die richtige Antwort gibt, wenn die beiden Daten aus unterschiedlichen Jahren stammen, zum Beispiel wenn ich es versuche 2007-02-01
und 2008-04-01
.
Gibt es eine bessere Lösung?
postgresql
date
time-series
postgresql-9.1
generate-series
f.ashouri
quelle
quelle
Antworten:
Kann ohne Konvertierung in / von int (aber stattdessen in / von Zeitstempel) durchgeführt werden
quelle
date_trunc
benötigt?Um eine Reihe von Daten zu generieren, ist dies der optimale Weg:
Zusätzliches
date_trunc()
wird nicht benötigt. Die Besetzung vondate
(day::date
) macht das implizit.Es macht aber auch keinen Sinn, Datumsliterale
date
als Eingabeparameter zu verwenden. Au contrairetimestamp
ist die beste Wahl . Der Leistungsvorteil ist gering, aber es gibt keinen Grund, ihn nicht zu nutzen. Und Sie müssen nicht unnötig DST-Regeln (Sommerzeit) in Verbindung mit der Konvertierung vondate
nachtimestamp with time zone
und zurück verwenden. Siehe unten.Äquivalente, weniger explizite kurze Syntax:
Oder mit der Set-Return-Funktion in der
SELECT
Liste:Das
AS
Schlüsselwort ist erforderlich in der letzten Variante würde Postgres die Spalte alias falsch interpretierenday
sonst. Und ich würde nicht diese Variante vor Postgres 10 raten - zumindest nicht mit mehr als einem Satz wiederkehr Funktion in der gleichenSELECT
Liste:(Abgesehen davon ist die letzte Variante normalerweise mit einem winzigen Vorsprung am schnellsten.)
Warum
timestamp [without time zone]
?Es gibt eine Reihe überladener Varianten von
generate_series()
. Derzeit (Postgres 11):(
numeric
Varianten wurden mit Postgres 9,5 hinzugefügt.) Die relevanten diejenigen Die letzten beiden sind in bold Mitnahmen und Zurückkehrentimestamp
/timestamptz
.Es gibt keine Variante, die nimmt oder zurückgibt
date
. Für die Rückkehr ist eine explizite Besetzung erforderlichdate
. Der Aufruf mittimestamp
Argumenten wird direkt in die beste Variante aufgelöst, ohne in Auflösungsregeln für Funktionstypen abzusteigen und ohne zusätzliche Umwandlung für die Eingabe.timestamp '2004-03-07'
ist übrigens vollkommen gültig. Der ausgelassene Zeitteil ist standardmäßig im00:00
ISO-Format.Dank der Auflösung des Funktionstyps können wir immer noch bestehen
date
. Das erfordert jedoch mehr Arbeit von Postgres. Es gibt eine implizite Besetzung vondate
bistimestamp
sowie eine vondate
bistimestamptz
. Wäre nicht eindeutig, abertimestamptz
ist „bevorzugt“ unter „Datum / Zeit - Typen“. Das Match wird also in Schritt 4d entschieden. ::Zusätzlich zu der zusätzlichen Arbeit bei der Auflösung von Funktionstypen wird eine zusätzliche Besetzung hinzugefügt,
timestamptz
die nicht nur die Kosten erhöht, sondern auch Probleme mit der Sommerzeit verursachen kann, die in seltenen Fällen zu unerwarteten Ergebnissen führen. (DST ist übrigens ein schwachsinniges Konzept, kann dies nicht genug betonen.) Verwandte:Ich habe der Geige Demos hinzugefügt, die den teureren Abfrageplan zeigen:
db <> hier fummeln
Verbunden:
quelle
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') :: DATE AS day;
Sie können Serien direkt mit Datumsangaben generieren. Keine Verwendung von Ints oder Zeitstempeln:
quelle
Sie können dies auch verwenden.
quelle