Pour générer une série de dates, c'est la manière optimale :
SELECT t.day::date
FROM generate_series(timestamp '2004-03-07'
, timestamp '2004-08-16'
, interval '1 day') AS t(day);
Aucun supplément date_trunc()
n'est nécessaire. Le cast to date
( day::date
) fait cela implicitement.
Mais il est également inutile de convertir des littéraux de date date
en paramètre d'entrée. Au contraire, timestamp
c'est le meilleur choix . L'avantage en termes de performances est faible, mais il n'y a aucune raison de ne pas en profiter. Et vous n'impliquez pas inutilement des règles DST (heure d'été) associées à la conversion de date
vers timestamp with time zone
et inversement. Voir ci-dessous.
Syntaxe courte équivalente, moins explicite:
SELECT day::date
FROM generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') day;
Ou avec la fonction de retour de set dans la SELECT
liste:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
Le AS
mot-clé est obligatoire dans la dernière variante, Postgres interpréterait mal l'alias de colonne day
sinon. Et je ne conseillerais pas cette variante avant Postgres 10 - du moins pas avec plus d'une fonction de retour d'ensemble dans la même SELECT
liste:
(Cela mis à part, la dernière variante est généralement la plus rapide par une petite marge.)
Pourquoi timestamp [without time zone]
?
Il existe un certain nombre de variantes surchargées de generate_series()
. Actuellement (Postgres 11):
SELECT oid::regprocedure AS function_signature
, prorettype::regtype AS return_type
FROM pg_proc
where proname = 'generate_series';
function_signature | return_type
: ------------------------------------------------- ------------------------------- | : --------------------------
generate_series (entier, entier, entier) | entier
generate_series (entier, entier) | entier
generate_series (bigint, bigint, bigint) | bigint
generate_series (bigint, bigint) | bigint
generate_series (numérique, numérique, numérique) | numérique
generate_series (numérique, numérique) | numérique
generate_series (horodatage sans fuseau horaire, horodatage sans fuseau horaire, intervalle) | horodatage sans fuseau horaire
generate_series (horodatage avec fuseau horaire, horodatage avec fuseau horaire, intervalle) | horodatage avec fuseau horaire
(Des numeric
variantes ont été ajoutées avec Postgres 9.5.) Les plus pertinentes sont les deux dernières en gras prenant et retournant timestamp
/ timestamptz
.
Il n'y a pas de variante prise ou retourdate
. Un cast explicite est nécessaire pour revenir date
. L'appel avec des timestamp
arguments résout directement la meilleure variante sans descendre dans les règles de résolution de type de fonction et sans conversion supplémentaire pour l'entrée.
timestamp '2004-03-07'
est parfaitement valide, btw. La partie de temps omise est par défaut au 00:00
format ISO.
Grâce à la résolution du type de fonction, nous pouvons encore passer date
. Mais cela nécessite plus de travail de la part de Postgres. Il y a un cast implicite de date
à timestamp
et un de date
à timestamptz
. Serait ambigu, mais timestamptz
est "préféré" parmi les "types de date / heure". Le match est donc décidé à l'étape 4d. :
Parcourez tous les candidats et conservez ceux qui acceptent les types préférés (de la catégorie de type du type de données d'entrée) dans la plupart des positions où la conversion de type sera requise. Conservez tous les candidats si aucun n'accepte les types préférés. S'il ne reste qu'un seul candidat, utilisez-le; sinon, passez à l'étape suivante.
En plus du travail supplémentaire dans la résolution des types de fonction, cela ajoute une conversion supplémentaire timestamptz
- ce qui non seulement ajoute plus de coûts, mais peut également introduire des problèmes avec DST conduisant à des résultats inattendus dans de rares cas. (L'heure d'été est un concept idiot, d'ailleurs, je ne saurais trop insister sur ce point.)
J'ai ajouté des démos au violon montrant le plan de requête le plus cher:
db <> violon ici
En relation: