Oracle SQL日期范围

时间:2016-06-23 09:51:04

标签: sql oracle date oracle11g

我有以下查询:

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-JUN-2016的结果。

为什么会这样?

4 个答案:

答案 0 :(得分:1)

我的猜测? value还存储时间价值?

使用TRAN_DATETIME

TRUNC()

答案 1 :(得分:0)

日期时间在内部被视为正确的时间戳。当您将日期提及为21-Jun-2016时,会将其视为21-Jun-2016 00:00:00.000。因此,它会在第一个条件中检查21-Jun-2016 00:00:00.00021-Jun-2016 00:00:00.000中的值,并解释您获得的输出。

答案 2 :(得分: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);
/

答案 3 :(得分: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 )