Um eine Reihe von Daten zu generieren, ist dies der optimale Weg:
SELECT t.day::date
FROM generate_series(timestamp '2004-03-07'
, timestamp '2004-08-16'
, interval '1 day') AS t(day);
Zusätzliches date_trunc()
wird nicht benötigt. Die Besetzung von date
( day::date
) macht das implizit.
Es macht aber auch keinen Sinn, Datumsliterale date
als Eingabeparameter zu verwenden. Au contraire timestamp
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 von date
nach timestamp with time zone
und zurück verwenden. Siehe unten.
Äquivalente, weniger explizite kurze Syntax:
SELECT day::date
FROM generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') day;
Oder mit der Set-Return-Funktion in der SELECT
Liste:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
Das AS
Schlüsselwort ist erforderlich in der letzten Variante würde Postgres die Spalte alias falsch interpretieren day
sonst. Und ich würde nicht diese Variante vor Postgres 10 raten - zumindest nicht mit mehr als einem Satz wiederkehr Funktion in der gleichen SELECT
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):
SELECT oid::regprocedure AS function_signature
, prorettype::regtype AS return_type
FROM pg_proc
where proname = 'generate_series';
Funktionssignatur | return_type
: --------------------------------------------- ------------------------------- | : --------------------------
generate_series (Ganzzahl, Ganzzahl, Ganzzahl) | ganze Zahl
generate_series (Ganzzahl, Ganzzahl) | ganze Zahl
generate_series (bigint, bigint, bigint) | Bigint
generate_series (bigint, bigint) | Bigint
generate_series (numerisch, numerisch, numerisch) | numerisch
generate_series (numerisch, numerisch) | numerisch
generate_series (Zeitstempel ohne Zeitzone, Zeitstempel ohne Zeitzone, Intervall) | Zeitstempel ohne Zeitzone
generate_series (Zeitstempel mit Zeitzone, Zeitstempel mit Zeitzone, Intervall) | Zeitstempel mit Zeitzone
( numeric
Varianten wurden mit Postgres 9,5 hinzugefügt.) Die relevanten diejenigen Die letzten beiden sind in bold Mitnahmen und Zurückkehren timestamp
/ timestamptz
.
Es gibt keine Variante, die nimmt oder zurückgibtdate
. Für die Rückkehr ist eine explizite Besetzung erforderlich date
. Der Aufruf mit timestamp
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 im 00: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 von date
bis timestamp
sowie eine von date
bis timestamptz
. Wäre nicht eindeutig, aber timestamptz
ist „bevorzugt“ unter „Datum / Zeit - Typen“. Das Match wird also in Schritt 4d entschieden. ::
Führen Sie alle Kandidaten durch und bewahren Sie diejenigen, die bevorzugte Typen (der Typkategorie des Eingabedatentyps) akzeptieren, an den meisten Positionen auf, an denen eine Typkonvertierung erforderlich ist. Behalten Sie alle Kandidaten, wenn keine bevorzugte Typen akzeptieren. Wenn nur noch ein Kandidat übrig ist, verwenden Sie ihn. Andernfalls fahren Sie mit dem nächsten Schritt fort.
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: