2016-06-23 5 views
1

У меня есть следующий запрос:Oracle SQL Дата Ranges

select * from sa_tran_head WHERE 
((TRAN_DATETIME) BETWEEN NVL(:STARTDATE, TRAN_DATETIME) AND NVL(:ENDDATE, TRAN_DATETIME)); 

Если я ставлю STARTDATE = 21-JUN-2016 and ENDDATE = 21-JUN-2016, он ничего не покажет. Когда я положил STARTDATE = 21-JUN-2016 and ENDDATE = 22-JUN-2016, он показывает результаты 21-ЮГО-2016.

Почему это происходит?

ответ

1

Мое предположение? TRAN_DATETIME также хранит значение времени?

Использование TRUNC():

select * from sa_tran_head 
WHERE TRUNC(TRAN_DATETIME) BETWEEN NVL(:STARTDATE, TRUNC(TRAN_DATETIME)) 
           AND NVL(:ENDDATE, TRUNC(TRAN_DATETIME)); 
+0

Использование 'TRUNC (TRAN_DATETIME)' будет означать, что любой индекс на этой колонке не могут быть использованы. Чтобы использовать индекс, вам понадобится индекс на основе функций. – MT0

+0

Чтобы использовать индекс, он может просто использовать свой текущий запрос с диапазоном между вчера и сегодня или что-то @ MT0 – sagi

0

Datetime внутренне рассматривают как соответствующую отметку времени. Когда вы указываете дату как 21-Jun-2016, она рассматривается как 21-Jun-2016 00:00:00.000. Следовательно, он проверяет значения в 21-Jun-2016 00:00:00.000 и 21-Jun-2016 00:00:00.000 в первом условии, объясняя вывод, который вы получаете.

+0

Oracle не имеет типа данных 'datetime'. У этого есть 'DATE' и' TIMESTAMP', и у них обоих есть компонент времени. OP говорит о 'DATE', и они не сохраняются с точностью до миллисекунды. – MT0

0

Может игнорироваться час, минуты и секунды? Посмотрите на пример:

create table t(v date) 
/
insert into t(v) values(to_date('2016-06-23 23:00:00', 'yyyy-mm-dd hh24:mi:ss')) 
/
-- no rows 
select * from t where 
v BETWEEN Nvl(to_date('2016-06-23 08:00:00', 'yyyy-mm-dd hh24:mi:ss'), v) 
    AND NVL(to_date('2016-06-23 08:00:00', 'yyyy-mm-dd hh24:mi:ss'), v); 
/
-- exactly one 
select * from t where 
v BETWEEN Nvl(to_date('2016-06-23 08:00:00', 'yyyy-mm-dd hh24:mi:ss'), v) 
    AND NVL(to_date('2016-06-24 08:00:00', 'yyyy-mm-dd hh24:mi:ss'), v); 
/
0

Oracle хранит даты в 7- or 8-byte data structure который всегда включает в себя компонент времени.

Когда у вас есть дата TO_DATE('21-JUN-2016', 'DD-MON-YYYY'), тогда Oracle создаст дату со временем 00:00:00.

Если вы:

WHERE TRAN_DATETIME BETWEEN TO_DATE('21-JUN-2016 00:00:00', 'DD-MON-YYYY HH24:MI:SS') 
         AND TO_DATE('21-JUN-2016 00:00:00', 'DD-MON-YYYY HH24:MI:SS') 

Тогда вы получите только результаты, которые на следующий день вы хотите и имеют временную составляющую 00:00:00.

Теперь вы можете использовать TRUNC(), чтобы установить компонент времени на 00:00:00:

WHERE TRUNC(TRAN_DATETIME) BETWEEN DATE '2016-06-21' AND DATE '2016-06-21' 

Однако, если существует индекс на TRAN_DATETIME колонке, то этот запрос не будет использовать его (это, однако, может использовать функциональный индекс на TRUNC(TRAN_DATETIME)).

Решение, которое может использовать индекс является:

WHERE TRAN_DATETIME >= :start_date 
AND TRAN_DATE  < :end_date + INTERVAL '1' DAY 

(Предполагая, что :start_date и :end_date являются переменной связывания передается с использованием временной составляющей 00:00:00 - что то, что вы, кажется, делают).

NVL Включение в отчетность:

WHERE (:start_date IS NULL OR TRAN_DATETIME >= :start_date) 
AND (:end_date IS NULL OR TRAN_DATE  < :end_date + INTERVAL '1' DAY) 
Смежные вопросы