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 datecomo 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 datepara timestamp with time zonee 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 SELECTlista:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
A ASpalavra-chave é necessária na última variante; daycaso 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 SELECTlista:
(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 numericvariantes 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 timestampargumentos é 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:00com 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 datepara timestampe um de datepara 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: