Eu tenho uma tabela chamada accounts
. Estou interessado em recuperar as contas cujo status não foi atualizado por mais de 10 dias. Pensei nessa consulta e pareceu funcionar, mas não tenho certeza se é a melhor abordagem:
SELECT * from accounts
WHERE status = 'PENDING_PAYMENT'
AND (date_part('day', (now() - status_updated_at)) > 10);
Uma coisa que eu não gosto nisso é o now()
papel. Seria ideal se now()
não fosse calculado para cada registro e, em vez disso, fosse um único valor de carimbo de data/hora calculado no início. Além disso, gostaria que este exemplo retornasse 1
:
Suponha que para um registro a status_updated_at
coluna tenha este valor: 2015-10-05 23:00:00
. E now()
retorna 2015-10-06 01:00:00
. Apesar de ser apenas algumas horas de diferença, eu quero que o resultado seja 1
.
Você pode simplificar sua expressão com a função
age()
(retornainterval
). Mas é muito mais eficiente usar uma expressão sargável para começar.Isso opera com a diferença de tempo exata (o tempo atual é relevante):
Para operar com dias corridos inteiros (até, mas excluindo meia-noite, fuso horário local):
Subtraindo
integer
dedate
rendimentosdate
, que podem ser comparadostimestamp
diretamente.Você parece estar pedindo o comportamento da segunda variante . A diferença é de mais de 10 dias.
Como funciona a avaliação?
Em resposta ao seu comentário.
CURRENT_DATE
é uma função especial que retorna a correntedate
(implementada internamente('now'::cstring)::date
na página 9.4). Existem muitas variantes do operador-
. Encontro 43 no catálogo do sistemapg_operator
em meu banco de dados de teste atual. O correto é escolhido para os tipos de dados dos operandos.Para
date - integer
, ointeger
número de dias é subtraído dedate
. O Postgres moderno armazena datas e timestamps comointeger
quantidades internamente. É muito barato transformar um no outro, somar/subtrair dias de/para umdate
, ou compará-los.O resultado da expressão é um
date
, whilestatus_updated_at
é umatimestamp
coluna. Eu estava assumindo uma atribuição implícita lançada no início, mas essa etapa nem é necessáriadate
etimestamp
compartilha um formato binário compatível e pode ser comparado diretamente. Existe uma variante do<
operador registrado paratimestamp < date
. Os valores da coluna podem ser testados "como estão", a expressão pode ser sargável, um índice btree pode ser usado.Relacionado:
Com
timestamptz
, a questão dos fusos horários seria adicionada à equação, que é complexa, mas normalmente se reduz a uma avaliação muito simples:Volatilidade de
now()
Seu desejo foi concedido . A
now()
família de funções (incluindoCURRENT_DATE
id definidoSTABLE
, ou seja,now()
retorna o mesmo valor dentro da mesma transação.