2016-06-23 10 views
1

ich die folgende Abfrage haben:Oracle SQL Datumsbereiche

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

Wenn ich STARTDATE = 21-JUN-2016 and ENDDATE = 21-JUN-2016 setzen, macht es nichts zeigen. Wenn ich STARTDATE = 21-JUN-2016 and ENDDATE = 22-JUN-2016 setze, zeigt es die Ergebnisse vom 21-JUN-2016.

Warum passiert das?

Antwort

1

Meine Schätzung? TRAN_DATETIME speichert auch den Zeitwert?

Verwendung TRUNC():

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

mit 'TRUNC (TRAN_DATETIME)' bedeutet, dass jeder Index für diese Spalte nicht verwendet werden kann. Um einen Index zu verwenden, benötigen Sie einen funktionsbasierten Index. – MT0

+0

Um einen Index zu verwenden, kann er einfach seine aktuelle Abfrage mit Bereich zwischen gestern und heute oder etwas @ MT0 – sagi

0

für Datum und Uhrzeit wird intern als richtiger Zeitstempel behandelt. Wenn Sie das Datum als 21-Jun-2016 angeben, wird es als 21-Jun-2016 00:00:00.000 behandelt. Daher überprüft es die Werte in 21-Jun-2016 00:00:00.000 und 21-Jun-2016 00:00:00.000 in der ersten Bedingung und erklärt die Ausgabe, die Sie erhalten.

+0

Oracle hat keine 'Datetime' Datentyp. Es hat 'DATE' und' TIMESTAMP' und beide haben eine Zeitkomponente. Das OP spricht über 'DATE's und diese werden nicht mit Millisekundengenauigkeit gespeichert. – MT0

0

Kann ich Stunden, Minuten und Sekunden ignorieren? Blick auf Beispiel:

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 speichert Daten in einem 7- or 8-byte data structure die immer eine Zeitkomponente enthält. Wenn Sie ein Datum TO_DATE('21-JUN-2016', 'DD-MON-YYYY') haben, erstellt Oracle das Datum mit der Uhrzeit 00:00:00.

Wenn Sie das tun:

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') 

Dann werden Sie nur Ergebnisse erhalten, die am Tag sind Sie und haben die Zeitkomponente 00:00:00.

Jetzt können Sie TRUNC() verwenden, um die Zeitkomponente zu 00:00:00 einzustellen:

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

Wenn es jedoch ein Index für die TRAN_DATETIME Spalte ist dann diese Abfrage wird es nicht verwenden (es könnte aber verwenden ein funktionsbasierter Index auf TRUNC(TRAN_DATETIME)).

Eine Lösung, die den Index verwenden kann, ist:

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

(Unter der Annahme, dass :start_date und :end_date sind Bindevariable mit einer Zeitkomponente von 00:00:00 übergeben - das ist, was Sie zu tun scheinen).

Einbeziehung der NVL Aussagen:

WHERE (:start_date IS NULL OR TRAN_DATETIME >= :start_date) 
AND (:end_date IS NULL OR TRAN_DATE  < :end_date + INTERVAL '1' DAY)