2014-09-01 134 views
0

我有2个SQL脚本。其中一个是这样的:在两个日期之间查找日期(最佳做法)

"Date" > '2014-04-11' AND "Date" <= '2014-04-12' 

另外一个是这样的:

"Date" BETWEEN '2014-04-11' AND '2014-04-12' 

现在我不知道是否有任何具体的最佳实践,其中一个原因做了另一种,如果他们中的一个是更好的出于某种明显的原因,我错过了沿途的某个地方。

+2

这两个查询不是同义词。 “BETWEEN”包含两个参数。我建议阅读这两篇文章; [BETWEEN和魔鬼有什么共同之处?](http://sqlblog.com/blogs/aaron_bertrand/archive/2011/10/19/what-do-between-and-the-devil-have-in-common .aspx)和[坏习惯踢:错误处理日期/范围查询](http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/16/bad-habits-to-kick-mishandling-日期范围-queries.aspx)。虽然是为SQL Server编写的,但许多参数仍然适用于Oracle。 – GarethD 2014-09-01 12:20:45

+0

不*相当*同义;第一个有'>'而不是'> =',这可能是一个错误。虽然你想要找到哪些数据,但并不完全清楚。 (我也建议你不要使用带引号的标识符或隐式日期转换,但两者都不在问题的范围之内)。 – 2014-09-01 12:26:05

+0

感谢您的链接,我一直在寻找这个主题,但我的“GoogleFu”在这件事上没有发现任何东西。 – 2014-09-01 14:33:38

回答

3

您正在寻求最佳实践。我认为,以下为最佳实践:

"Date" >= DATE '2014-04-11' AND "Date" < DATE '2014-04-12' + 1 

首先,请注意使用DATE关键字。您的问题是关于日期,但您使用的是Oracle不直接支持的日期格式。令人高兴的是,Oracle支持符合ISO标准格式的ANSI标准DATE关键字。

其次,我添加了一个+1,以便您可以看到时间段的结束,这可能是您想要在代码中看到的内容。它不应该影响性能,因为+ 1是常量。

第三,日期常量具有时间分量。如果没有指定,则是在日期的午夜。因此,表达式:

"Date" BETWEEN '2014-04-11' AND '2014-04-12' 

是真的:

"Date" >= TIMESTAMP '2014-04-11 00:00:00' AND "Date" <= TIMESTAMP '2014-04-12 00:00:00' 

也就是说,从后来的日期恰好一个时间包括,在午夜的第一瞬间。这通常不是你想要的。 Oracle通过两种方式使此问题变得更糟:

  1. date数据类型包含一个时间组件。
  2. 呈现date值的默认方式没有时间分量。

所以,为了安全,请使用以下规则:

  • 不要使用日期between
  • 第一次使用>=
  • 用户<第二。

Aaron Bertrand在这个话题上有一个blog。虽然它特别针对SQL Server,但许多想法都适用于Oracle - 尤其是因为Oracle中的date数据类型包含时间。

+0

“日期”是抽象的,但由于在这种情况下原始的列名没有意义,我冒昧地将它改为更可读的东西,尽管不太正确。 – 2014-09-01 14:32:31

1
SQL> create table date_tab as select sysdate + level d from dual connect by rownum < 10; 

Table created. 

之间使用:

SQL> set autotrace traceonly 
SQL> select * from date_tab where d between sysdate + 1 and sysdate + 3; 


Execution Plan 
---------------------------------------------------------- 
Plan hash value: 290508398 

... 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - filter([email protected]!+1<[email protected]!+3) 
    2 - filter("D">[email protected]!+1 AND "D"<[email protected]!+3) 

使用日期间隔:

SQL> select * from date_tab where d > sysdate + 1 and d <= sysdate + 3; 


Execution Plan 
---------------------------------------------------------- 
Plan hash value: 290508398 

... 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - filter([email protected]!+1<[email protected]!+3) 
    2 - filter("D">[email protected]!+1 AND "D"<[email protected]!+3) 

正如你所看到的,Oracle优化重写between谓词"D">[email protected]!+1 AND "D"<[email protected]!+3所以如果你使用第二个变种Oracle执行比第一个变体少一步。

相关问题