Para gerar uma série de datas, esta é a maneira ideal :
SELECT t.day::date
FROM generate_series(timestamp '2004-03-07'
, timestamp '2004-08-16'
, interval '1 day') AS t(day);
Adicional date_trunc()
não é necessário. A conversão para date
( day::date
) faz isso implicitamente.
Mas também não faz sentido converter literais de data date
como parâmetro de entrada. Au contraire, timestamp
é a melhor escolha . A vantagem em desempenho é pequena, mas não há razão para não aproveitá-la. E você não desnecessariamente envolver DST (horário de verão) Regras juntamente com a conversão de date
para timestamp with time zone
e volta. Ver abaixo.
Sintaxe curta equivalente e menos explícita:
SELECT day::date
FROM generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') day;
Ou com a função set-return na SELECT
lista:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
A AS
palavra-chave é necessária na última variante; day
caso contrário , o Postgres interpretaria incorretamente o alias da coluna . E eu não recomendaria essa variante antes do Postgres 10 - pelo menos não com mais de uma função de retorno de conjunto na mesma SELECT
lista:
(Tirando isso, a última variante é normalmente mais rápida por uma pequena margem.)
Por quê timestamp [without time zone]
?
Existem várias variantes sobrecarregadas de generate_series()
. Atualmente (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 (inteiro, inteiro, inteiro) | inteiro
generate_series (inteiro, inteiro) | inteiro
generate_series (bigint, bigint, bigint) | bigint
generate_series (bigint, bigint) | bigint
generate_series (numérico, numérico, numérico) | numérico
generate_series (numérico, numérico) | numérico
generate_series (timestamp sem fuso horário, timestamp sem fuso horário, intervalo) | carimbo de data / hora sem fuso horário
generate_series (timestamp com fuso horário, timestamp com fuso horário, intervalo) | carimbo de data / hora com fuso horário
(as numeric
variantes foram adicionadas com Postgres 9.5.) Os relevantes são os dois últimos em negrito e retornando timestamp
/ timestamptz
.
Não há variante de pegar ou devolverdate
. Um elenco explícito é necessário para retornar date
. A chamada com timestamp
argumentos é resolvida para a melhor variante diretamente, sem cair nas regras de resolução de tipo de função e sem conversão adicional para a entrada.
timestamp '2004-03-07'
é perfeitamente válido, aliás. A parte do tempo omitida é padronizada 00:00
com o formato ISO.
Graças à resolução do tipo de função ainda podemos passar date
. Mas isso requer mais trabalho do Postgres. Há um elenco implícito de date
para timestamp
e um de date
para timestamptz
. Seria ambíguo, mas timestamptz
é "preferido" entre os "tipos de data / hora". Portanto, a partida é decidida na etapa 4d. :
Percorra todos os candidatos e mantenha aqueles que aceitam tipos preferidos (da categoria de tipo do tipo de dados de entrada) na maioria das posições onde a conversão de tipo será necessária. Mantenha todos os candidatos se nenhum aceitar os tipos preferidos. Se restar apenas um candidato, use-o; caso contrário, continue para a próxima etapa.
Além do trabalho extra na resolução do tipo de função, isso adiciona um elenco extra timestamptz
- o que não apenas adiciona mais custo, mas também pode introduzir problemas com o DST, levando a resultados inesperados em casos raros. (DST é um conceito idiota, aliás, não consigo enfatizar isso o suficiente.) Relacionado:
Eu adicionei demonstrações ao violino mostrando o plano de consulta mais caro:
db <> fiddle aqui
Relacionado: