2010-03-03 131 views
46

我正在使用oracle数据库。我想执行一个查询来检查两个日期之间的数据。Oracle date“Between”查询

NAME    START_DATE  
------------- ------------- 
Small Widget  15-JAN-10 04.25.32.000000 PM  
Product 1   17-JAN-10 04.31.32.000000 PM 



select * from <TABLENAME> where start_date 
BETWEEN '15-JAN-10' AND '17-JAN-10' 

但我没有从上面的查询得到任何结果。我想我必须使用“like”和“%”。但我不知道在哪里使用它们。请在此点亮一些灯。

在此先感谢。

回答

74

从输出来看,它看起来像你将START_DATE定义为时间戳。如果这是一个正常的日期,Oracle将能够处理隐式转换。但是,因为它不是你需要明确地将这些字符串转换为日期。

SQL> alter session set nls_date_format = 'dd-mon-yyyy hh24:mi:ss' 
    2/

Session altered. 

SQL> 
SQL> select * from t23 
    2 where start_date between '15-JAN-10' and '17-JAN-10' 
    3/

no rows selected 

SQL> select * from t23 
    2 where start_date between to_date('15-JAN-10') and to_date('17-JAN-10') 
    3/

WIDGET       START_DATE 
------------------------------ ---------------------- 
Small Widget     15-JAN-10 04.25.32.000  

SQL> 

但是我们仍然只得到一行。这是因为START_DATE有一个时间元素。如果我们不指定时间组件,Oracle默认它是午夜。这是罚款的BETWEEN的一面,但不是为直到方:

SQL> select * from t23 
    2 where start_date between to_date('15-JAN-10') 
    3      and to_date('17-JAN-10 23:59:59') 
    4/

WIDGET       START_DATE 
------------------------------ ---------------------- 
Small Widget     15-JAN-10 04.25.32.000 
Product 1      17-JAN-10 04.31.32.000 

SQL> 

编辑

如果你不能在时间成分通过有一对夫妇的选择。一种是改变WHERE子句从标准中删除了时间元素:

where trunc(start_date) between to_date('15-JAN-10') 
          and to_date('17-JAN-10') 

这可能会对性能产生影响,因为它在不够格START_DATE任何B树索引。你需要建立一个基于函数的索引。

或者你可以在时间元素添加到日期代码:

where start_date between to_date('15-JAN-10') 
        and to_date('17-JAN-10') + (86399/86400) 

因为这些问题很多人喜欢通过检查日期界限这样来避免使用between

where start_date >= to_date('15-JAN-10') 
and start_date < to_date('18-JAN-10') 
+0

我无法通过时间唯一的日期。 – 2010-03-03 09:18:01

+0

哇,它工作的很好APC ...非常感谢您的支持 – 2010-03-03 12:18:47

+0

@APC在ORACLE 11中工作得像魅力G – Alex 2016-08-05 15:10:33

20

你需要转换的实际日期,而不是字符串,试试这个:

SELECT * 
FROM <TABLENAME> 
WHERE start_date BETWEEN TO_DATE('2010-01-15','YYYY-MM-DD') AND TO_DATE('2010-01-17', 'YYYY-MM-DD'); 

编辑处理的格式规定:

SELECT * 
FROM <TABLENAME> 
WHERE start_date BETWEEN TO_DATE('15-JAN-10','DD-MON-YY') AND TO_DATE('17-JAN-10','DD-MON-YY'); 
+0

感谢您的迅速回复。但是我以这种格式“17-JAN-10”从动作文件中获取From和To date。所以它是这样的: SELECT \t * FROM uson_assetaccess WHERE accessdate BETWEEN TO_DATE('17 -FEB-10','dd-MMM-yy')和TO_DATE('17 -FEB-10','dd-MMM- YY'); 但是我得到一个错误:ORA-01821:日期格式无法识别 – 2010-03-03 06:54:27

+0

您只需使用不同的格式说明符,用“MON”替换“MMM”,请参阅我的编辑。 – 2010-03-03 06:57:30

+0

再次感谢您立即回复。但我已经使用该查询但现在日期格式错误消失了。现在我没有发现数据错误,即使数据在表中。我认为在桌上的日期与时间有关,但我们仅以日期发送。是因为这个原因吗?请澄清 – 2010-03-03 07:02:28

3

正如APC正确指出的那样,start_date列看起来像是TIMESTAMP,但它也可能是TIMESTAMP WITH LOCAL TIMEZONE或TIMESTAMP WITH TIMEZONE数据类型。如果您的数据库服务器与您自己处于不同的时区,这些可能会影响您对数据执行的任何查询。但是,让我们保持简单并假设您与服务器位于同一时区。首先,为了给您信心,请检查start_date是否为TIMESTAMP数据类型。

使用SQLPlus DESCRIBE命令(或IDE中的等效项)来验证此列是否为TIMESTAMP数据类型。

DESCRIBE MYTABLE

应该报告:

Name  Null? Type 
----------- ----- ------------ 
NAME    VARHAR2(20) 
START_DATE  TIMESTAMP 

如果报告为一个类型= TIMESTAMP,那么你可以用最简单的TO_TIMESTAMP日期转换查询您的日期范围,一个需要没有参数(或图片)。

我们使用TO_TIMESTAMP确保优化程序考虑START_DATE列中的任何索引。 APC的回答还指出,基于函数的索引可能已经创建在该列上,并且会影响SQL谓词,但我们无法对此查询中的评论发表评论。如果您想知道如何找出已应用于表格的索引,请发布另一个问题,我们可以分别回答。

因此,假设有在起始日期指数,这是一个TIMESTAMP数据类型和您想要的优化考虑它,你的SQL是:

select * from mytable where start_date between to_timestamp('15-JAN-10') AND to_timestamp('17-JAN-10')+.9999999 

+.999999999非常接近,但是,这不是” t相当于1,因此17-JAN-10的转换将尽可能接近午夜,因此您查询时会返回两行。

数据库将看到从15-JAN-10之间为00:00:00:000000017-JAN-10 23:59:59:99999,因此将包括所有的日期从15日无论时间戳的时间组件如何。

希望有所帮助。

Dazzer

1

日期查询

SELECT * 
    FROM emp 
    WHERE HIREDATE between to_date (to_char(sysdate, 'yyyy') ||'/09/01', 'yyyy/mm/dd') 
    AND to_date (to_char(sysdate, 'yyyy') + 1|| '/08/31', 'yyyy/mm/dd'); 
1

之间下面的查询,也可以使用:

select * 
    from t23 
where trunc(start_date) between trunc(to_date('01/15/2010','mm/dd/yyyy')) and trunc(to_date('01/17/2010','mm/dd/yyyy')) 
+2

如果一个表很大并且日期列被索引,那么应该避免使用'to_date(' 01/15/2010','mm/dd/yyyy')和to_date('01/17/2010','mm/dd/yyyy')+ 1'。 – Dmitry 2015-03-30 13:47:28