【问题标题】:Oracle date "Between" QueryOracle 日期“Between”查询
【发布时间】:2011-01-23 01:50:40
【问题描述】:

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

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”和“%”。但我不知道在哪里使用它们。请在这点上点灯。

提前致谢。

【问题讨论】:

    标签: sql oracle oracle10g where-clause date-arithmetic


    【解决方案1】:

    您需要将它们转换为实际日期而不是字符串,试试这个:

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

    【讨论】:

    • 感谢您的快速回复。但我从这种格式“17-JAN-10”的操作文件中获取 From 和 To 日期。所以 itried 像这样: SELECT * FROM uson_assetaccess WHERE accessdate BETWEEN TO_DATE('17-FEB-10','dd-MMM-yy') AND TO_DATE('17-FEB-10', 'dd-MMM-yy');但我得到一个错误:ORA-01821:日期格式无法识别
    • 您只需要使用不同的格式说明符,将“MMM”替换为“MON”,请参阅我的编辑。
    • 再次感谢您的即时回复。但是我已经使用了那个查询但是现在日期格式错误消失了。现在我没有找到数据错误,即使表中有数据。我认为表格中的日期是有时间的,但我们只发送日期。是不是因为这个原因?请澄清
    • 这取决于您在一天中关注的位置。我认为仅指定日期将使其仅从/到当天的午夜(开始)。如果您希望它包含 1 月 17 日的任何内容,则需要添加时间,因此请进行查询的第二部分:AND TO_DATE('17-JAN-10 23:59:59','DD-MON-YY HH:MI:SS')
    • 过滤日期时无法获取时间。
    【解决方案2】:

    从您的输出来看,您似乎已将 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 会将其默认为午夜。这对于 BETWEENfrom 一侧来说很好,但对于 until 一侧则不行:

    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-tree 索引的资格。您将需要构建一个基于函数的索引。

    或者,您可以将时间元素添加到代码中的日期:

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

    【讨论】:

    • 我无法通过仅时间日期。
    【解决方案3】:

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

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

    例如

    描述我的表

    应该报告:

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

    如果报告为 Type = TIMESTAMP,那么您可以使用最简单的 TO_TIMESTAMP 日期转换来查询您的日期范围,该转换不需要参数(或图片)。

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

    所以,假设 start_date 上有一个索引,它是一个 TIMESTAMP 数据类型,并且您希望优化器考虑它,您的 SQL 将是:

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

    +.999999999 非常接近但不完全是 1,因此 17-JAN-10 的转换将尽可能接近当天的午夜,因此您查询返回两行。

    数据库将看到从 15-JAN-10 00:00:00:000000017-JAN-10 23:59:59:99999 的 BETWEEN因此将包括 2010 年 1 月 15 日、16 日和 17 日的所有日期,无论时间戳的时间部分如何。

    希望对您有所帮助。

    炫酷

    【讨论】:

      【解决方案4】:

      查询之间的日期

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

      【讨论】:

        【解决方案5】:

        也可以使用以下查询:

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

        【讨论】:

        • 如果表很大,并且日期列被索引,你应该避免使用表达式,而是使用start_date between to_date('01/15/2010','mm/dd/yyyy') and to_date('01/17/2010','mm/dd/yyyy') + 1
        猜你喜欢
        • 2012-09-23
        • 1970-01-01
        • 1970-01-01
        • 2019-10-19
        • 1970-01-01
        • 2015-04-27
        • 2014-06-09
        • 1970-01-01
        • 2021-10-21
        相关资源
        最近更新 更多