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 datecome 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 datea timestamp with time zonee 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 SELECTnell'elenco:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
La ASparola chiave è obbligatoria nell'ultima variante, dayaltrimenti 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 SELECTlista:
(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
( numericsono 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 timestampargomenti 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:00con 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 datea timestampe uno da datea 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: