Tenho uma condição em que desejo obter resultados entre duas datas:
start_time: 2025-01-02
end_time: 2025-04-27
O problema é que não recebo o resultado 2025-04-27 , recebo 2025-04-26 , então termina um dia antes. Também quero obter o horário 2025-04-27.
O que estou fazendo errado?
SELECT l.id AS aslocation_id
, l.name
, lo.id
, lo.start_time
, lo.end_time
, lo.leader_id
, lo.is_storno
, lo.storno_at
, lo.storno_by
, lo.employees_need
, lo.created_at
FROM location_orders AS lo
JOIN location AS l ON l.id = lo.location_id
WHERE lo.tenant_id = 321
AND lo.deleted_by IS NULL
AND lo.start_time >= '2025-01-02'
AND lo.end_time <= '2025-04-27'
ORDER BY lo.start_time DESC
, lo.id DESC
LIMIT 50;
Você pode pedir ao Postgres para explicar isso adicionando "
explain analyze verbose
antes" à consulta. Depois disso, ele mostrará um plano com algo assim:Está tornando seu
'2025-01-02'
e'2025-04-27'
umtimestamp
tipo, não umdate
. Isso está acontecendo porque suas colunas e já sãostart_time
s e as constantes de entrada são do tipo .end_time
timestamp
unknown
Você
pg_operator
pode ver que há 3>=
variantes diferentes de operadores para comparações com atimestamp
à esquerda:Esta lista é usada para adivinhar o tipo correto para o seu operando direito, a
unknown
constante string. Embora exista uma que aceita adate
à direita, a regra de conversão de tipo 2.a diz que é preferível fazer com que eles correspondam:Mesmo que não tenha sido convertido e você o tenha feito explicitamente
<= '2025-04-27'::date
, quando comparado ao seutimestamp
campo, a sequência de caracteres com aparência de data à direita conta como meia-noite naquela data.Como já foi dito, é mais fácil se você apenas excluir o limite superior e aumentar a data:
demo em db<>fiddle
O problema é esta expressão:
É equivalente a isto:
Portanto, qualquer valor
end_time
com um componente de tempo após o primeiro momento do dia é excluído.A solução é um intervalo semiaberto , com um limite superior exclusivo (em vez de inclusivo) definido para o dia seguinte à data desejada:
Observe o operador de comparação
<
rather than .<=
Isso é preferível à conversão
lo.end_time
como Cate, como sugerido anteriormente, porque a opção de conversão força o banco de dados a calcular o resultado da conversão para cada linha da tabela que atenda aos outros critérios, mesmo aquelas que você não precisará. Caso contrário, como ele poderia concluir a verificação condicional para saber se você precisará da linha? Além disso, a conversão de Data tende a interferir em qualquer índice para esta coluna que poderia ter ajudado, o que prejudica o desempenho do banco de dados.O problema que você está enfrentando provavelmente se deve à maneira como datas e horas estão sendo tratadas na sua consulta SQL. A
lo.end_time <= '2025-04-27'
condição incluirá apenas registros quelo.end_time
estejam exatamente no início de2025-04-27 00:00:00
. Selo.end_time
houver algum componente de tempo mais tarde no dia (por exemplo,2025-04-27 12:00:00
), ele será excluído.Para garantir que você inclua todos os registros até o final de 2025-04-27,
1. Ajuste o horário de término para incluir o dia inteiro
Você pode ajustar sua consulta para incluir o dia inteiro
2025-04-27
comparandolo.end_time
com2025-04-28 00:00:00
:2. Use funções de data para incluir o dia inteiro
**Recebi uma ajuda do chatgpt