Per generare una serie di date questo è il modo ottimale :
SELECT t.day::date
FROM generate_series(timestamp '2004-03-07'
, timestamp '2004-08-16'
, interval '1 day') AS t(day);
Ulteriori date_trunc()
non è necessaria. Il cast di date
( day::date
) lo fa implicitamente.
Ma non ha nemmeno senso eseguire il cast di valori letterali di data date
come parametro di input. Al contrario, timestamp
è la scelta migliore . Il vantaggio in termini di prestazioni è piccolo, ma non c'è motivo per non prenderlo. E non è necessario coinvolgere inutilmente le regole DST (ora legale) accoppiate con la conversione da date
a timestamp with time zone
e viceversa. Vedi sotto.
Sintassi breve equivalente, meno esplicita:
SELECT day::date
FROM generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') day;
O con la funzione set-return SELECT
nell'elenco:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
La AS
parola chiave è obbligatoria nell'ultima variante, day
altrimenti Postgres interpreterebbe erroneamente l'alias della colonna . E non consiglierei quella variante prima di Postgres 10, almeno non con più di una funzione di restituzione di set nella stessa SELECT
lista:
(A parte questo, l'ultima variante è in genere più veloce con un piccolo margine.)
Perché timestamp [without time zone]
?
Esistono numerose varianti sovraccariche di generate_series()
. Attualmente (Postgres 11):
SELECT oid::regprocedure AS function_signature
, prorettype::regtype AS return_type
FROM pg_proc
where proname = 'generate_series';
function_signature | tipo_ritorno
: ------------------------------------------------- ------------------------------- | : --------------------------
generate_series (integer, integer, integer) | numero intero
generate_series (integer, integer) | numero intero
generate_series (bigint, bigint, bigint) | bigint
generate_series (bigint, bigint) | bigint
generate_series (numeric, numeric, numeric) | numerico
generate_series (numerico, numerico) | numerico
generate_series (timestamp senza fuso orario, timestamp senza fuso orario, intervallo) | timestamp senza fuso orario
generate_series (timestamp con fuso orario, timestamp con fuso orario, intervallo) | timestamp con fuso orario
( numeric
sono state aggiunte varianti con Postgres 9.5.) Quelle rilevanti sono le ultime due in grassetto prendere e restituire timestamp
/ timestamptz
.
Non è possibile prendere o restituire variantidate
. È necessario un cast esplicito per tornare date
. La chiamata con timestamp
argomenti si risolve direttamente nella variante migliore senza scendere nelle regole di risoluzione del tipo di funzione e senza cast aggiuntivo per l'input.
timestamp '2004-03-07'
è perfettamente valido, btw. La parte temporale omessa viene impostata per impostazione predefinita 00:00
con il formato ISO.
Grazie alla risoluzione del tipo di funzione possiamo ancora passare date
. Ma questo richiede più lavoro da Postgres. C'è un cast implicito da date
a timestamp
e uno da date
a timestamptz
. Sarebbe ambiguo, ma timestamptz
è "preferito" tra i "tipi di data / ora". Quindi la partita viene decisa al passaggio 4d. :
Scorri tutti i candidati e mantieni quelli che accettano i tipi preferiti (della categoria del tipo del tipo di dati di input) nella maggior parte delle posizioni in cui sarà richiesta la conversione del tipo. Mantieni tutti i candidati se nessuno accetta i tipi preferiti. Se rimane un solo candidato, usalo; altrimenti vai al passaggio successivo.
Oltre al lavoro extra nella risoluzione del tipo di funzione, questo aggiunge un cast extra a timestamptz
- che non solo aggiunge più costi, ma può anche introdurre problemi con DST che portano a risultati imprevisti in rari casi. (L'ora legale è un concetto stupido, btw, non posso sottolinearlo abbastanza.)
Ho aggiunto demo al violino che mostrano il piano di query più costoso:
db <> fiddle qui
Relazionato: