Para generar una serie de fechas esta es la forma óptima :
SELECT t.day::date
FROM generate_series(timestamp '2004-03-07'
, timestamp '2004-08-16'
, interval '1 day') AS t(day);
No date_trunc()
se necesita más. La conversión a date
( day::date
) lo hace implícitamente.
Pero tampoco tiene sentido convertir literales de fecha date
como parámetro de entrada. Au contraire, timestamp
es la mejor opción . La ventaja en el rendimiento es pequeña, pero no hay razón para no aprovecharla. Y ni falta que involucra a horario de verano (horario de verano) Normas junto con la conversión de date
a timestamp with time zone
ida y vuelta. Vea abajo.
Sintaxis corta equivalente, menos explícita:
SELECT day::date
FROM generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') day;
O con la función de devolución de conjuntos en la SELECT
lista:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
La AS
palabra clave es necesaria en la última variante, de lo day
contrario , Postgres malinterpretaría el alias de la columna . Y no recomendaría esa variante antes de Postgres 10, al menos no con más de una función de retorno de conjunto en la misma SELECT
lista:
(Aparte de eso, la última variante suele ser la más rápida por un pequeño margen).
¿Por qué timestamp [without time zone]
?
Hay una serie de variantes sobrecargadas de generate_series()
. Actualmente (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 (entero, entero, entero) | entero
generate_series (entero, entero) | entero
generate_series (bigint, bigint, bigint) | Empezando
generate_series (bigint, bigint) | Empezando
generate_series (numérico, numérico, numérico) | numérico
generate_series (numérico, numérico) | numérico
generate_series (marca de tiempo sin zona horaria, marca de tiempo sin zona horaria, intervalo) | marca de tiempo sin zona horaria
generate_series (marca de tiempo con zona horaria, marca de tiempo con zona horaria, intervalo) | marca de tiempo con zona horaria
( numeric
Se agregaron variantes con Postgres 9.5.) Las relevantes son las dos últimas en negrita tomando y regresando timestamp
/ timestamptz
.
No hay ninguna variante de recogida o devolucióndate
. Se necesita un elenco explícito para regresar date
. La llamada con timestamp
argumentos se resuelve directamente en la mejor variante sin descender a las reglas de resolución de tipo de función y sin conversión adicional para la entrada.
timestamp '2004-03-07'
es perfectamente válido, por cierto. La parte de tiempo omitida tiene por defecto el 00:00
formato ISO.
Gracias a la resolución del tipo de función todavía podemos pasar date
. Pero eso requiere más trabajo de Postgres. Hay un reparto implícito de date
a timestamp
así como uno de date
a timestamptz
. Sería ambiguo, pero timestamptz
es "preferido" entre los "tipos de fecha / hora". Entonces, la coincidencia se decide en el paso 4d. :
Revise todos los candidatos y mantenga aquellos que aceptan tipos preferidos (de la categoría de tipo del tipo de datos de entrada) en la mayoría de las posiciones donde se requerirá la conversión de tipo. Conserve todos los candidatos si ninguno acepta los tipos preferidos. Si solo queda un candidato, utilícelo; de lo contrario, continúe con el siguiente paso.
Además del trabajo adicional en la resolución del tipo de función, esto agrega una conversión adicional timestamptz
, lo que no solo agrega más costos, sino que también puede presentar problemas con DST que conducen a resultados inesperados en casos excepcionales. (El horario de verano es un concepto estúpido, por cierto, no puedo enfatizar esto lo suficiente).
Agregué demostraciones al violín que muestran el plan de consulta más caro:
db <> violín aquí
Relacionado: