查找两个日期之间的日期(最佳实践)

Posted

技术标签:

【中文标题】查找两个日期之间的日期(最佳实践)【英文标题】:Finding dates between two dates (Best practice) 【发布时间】:2014-09-01 12:16:31 【问题描述】:

我有 2 个 SQL 脚本。像这样的:

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

另一个是这样的:

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

现在我想知道是否有任何特定的最佳实践,一个做一个优于另一个的原因,如果由于某些明显的原因,其中一个更好,我错过了某个地方。

【问题讨论】:

这两个查询不是同义词。 BETWEEN 包含两个参数。我建议阅读这两篇文章; What do BETWEEN and the devil have in common? 和 Bad habits to kick : mis-handling date / range queries。尽管是为 SQL Server 编写的,但许多参数对 Oracle 仍然有效。 不是相当的同义词;第一个有&gt; 而不是&gt;=,这可能是问题中的错误。不过,您想要找到哪些数据并不完全清楚。 (我还建议您不要使用带引号的标识符或隐式日期转换,但两者都超出了问题的范围)。 感谢您提供的链接,我一直在寻找这个主题,但我的“GoogleFu”在这件事上没有找到任何东西。 【参考方案1】:

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

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

首先,注意DATE 关键字的使用。您的问题是关于 dates 的,但您使用的是 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 在两个方面使这个问题变得更糟:

    date 数据类型包含时间组件。 呈现date 值的默认方式没有时间组件。

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

不要在约会时使用between。 第一次约会时使用&gt;=。 第二个用户&lt;

Aaron Bertrand 有一个 blog 正是关于这个主题的。虽然它专门针对 SQL Server,但其中许多想法适用于 Oracle ——尤其是因为 Oracle 中的 date 数据类型包括时间。

【讨论】:

"Date" 是抽象的,但由于原始列名在这种情况下没有意义,我冒昧地将其更改为更易读的名称,尽管不是那么正确。【参考方案2】:
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(SYSDATE@!+1<=SYSDATE@!+3)
   2 - filter("D">=SYSDATE@!+1 AND "D"<=SYSDATE@!+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(SYSDATE@!+1<SYSDATE@!+3)
   2 - filter("D">SYSDATE@!+1 AND "D"<=SYSDATE@!+3)

如您所见,oracle 优化器将between 谓词重写为"D"&gt;=SYSDATE@!+1 AND "D"&lt;=SYSDATE@!+3 因此,如果您使用第二个变体,oracle 执行的操作比第一个变体少一步。

【讨论】:

以上是关于查找两个日期之间的日期(最佳实践)的主要内容,如果未能解决你的问题,请参考以下文章

NSDate 创建没有时间元素的日期的最佳实践

BigQuery 表设计最佳实践:日期分区和分片的组合?

DWH 建模最佳实践:二维使用的日期键

初始化日期时间值同时避免代码重复的最佳实践

bson.json_util 日期时间编码和解码最佳实践

最佳实践 - 基于用户选择构建查询