两个日期之间的Oracle SQL数据

时间:2016-04-18 18:52:18

标签: sql oracle date

我正在查看一些SQL并尝试了解它正在尝试做什么。我被告知它会在午夜和今天的昨天之间返回数据。有人可以将以下摘录翻译成简单的英语吗?

SELECT ...
FROM ...
WHERE CREATEDATE >=TO_DATE(TRUNC(SYSDATE-1) || ' 00:00:00', 'DD-MON-YY HH24:MI:SS')
AND CREATEDATE <=TO_DATE(TRUNC(SYSDATE-1) || ' 23:59:59', 'DD-MON-YY HH24:MI:SS')

除非我将底线更改为:

,否则这似乎无效
AND CREATEDATE <=TO_DATE(TRUNC(SYSDATE) || ' 23:59:59', 'DD-MON-YY HH24:MI:SS')

理解此代码的任何帮助都将受到赞赏。

2 个答案:

答案 0 :(得分:5)

谓词看起来比他们需要的更复杂。

为什么这不会返回您要返回的结果?

   WHERE CREATEDATE >= TRUNC(SYSDATE-1)
     AND CREATEDATE <  TRUNC(SYSDATE)

在&#34; plain english&#34;中解释一下,这个SELECT语句返回的所有三个表达式:

 SELECT SYSDATE
      , TRUNC(SYSDATE)
      , TRUNC(SYSDATE-1)
   FROM DUAL

返回DATE值(Oracle数据类型为DATE的值)。

  -------------------  -------------------  -------------------
  2016-04-16 13:59:26  2016-04-16 00:00:00  2016-04-15 00:00:00

我们没有看到的是CREATEDATE的数据类型。显然,我们希望将其定义为DATE。但是,如果您已将其声明为VARCHAR并且存储的字符串格式类似于&#39; 16-APR-2016 13:59:26&#39;然后&#34;似乎无法工作,除非&#34;你观察的问题只是冰山一角。

(如果CREATEDATE被声明为VARCHAR而不是DATE,则可以很容易地解释您正在观察的行为。)

如果您的SQL 在写入时正常工作,则它取决于NLS_DATE_FORMAT的当前设置。也就是说,您的SQL可以通过相对无害的语句轻松破解,例如:

 ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD' ;

当前查询中表达式的某些组件的概述...

  • SYSDATE以DATE

  • 的形式返回当前日期和时间
  • SYSDATE-1从当前日期和时间减去1天并返回日期

  • TRUNC(<dateexpr>)&#34;停止&#34;来自DATE值的时间分量,仅返回时间设置为午夜的日期部分

  • ||是字符串连接运算符

注意:使用DATE表达式执行字符串连接需要Oracle执行隐式TO_CHAR转换.Oracle使用NLS_DATE_FORMAT作为默认格式模型。)

  • '单引号括起字符串文字

TO_DATE函数的第二个参数是格式模型。

  • DD是两位数的日期(例如07或16)
  • MON是本月的三个字母缩写
  • YY是年份的两个字符代表,含有隐含的世纪(
  • HH24是两位数小时(24小时制),00至23
  • MI是两位数分钟,00到59
  • SS是两位数秒,00到59

注意:我们已经修复 Y2K问题?我们为什么要重新创建它?)

我认为最重要的事情要了解当前的SQL:它使用的表达式比需要的更复杂。而且我认为这些表达方式在三个方面被打破了:

  • 依赖于NLS_DATE_FORMAT,隐式TO_CHAR函数与TO_DATE函数中的显式格式模型匹配

  • 没有理由使用两个字符的年份我们可以轻松使用四位数年份。特别是当首先不需要将DATE值转换为字符串时。

  • 使用&lt; =比较而不是&lt;比较,取决于日期时间类型的最大精度为1秒,当我们可以轻松指定&#34;小于&#34;第二天的午夜,带有处理小数秒的模式。

如果将CREATEDATE声明为VARCHAR,则以另一种方式将其破坏...比较将作为字符串比较执行。对于比较右侧的表达式,存在隐式TO_CHAR转换。这些转换(再次)依赖于NLS_DATE_FORMAT设置。使用古老的Oracle默认设置DD-MON-YY,字符串比较将在某种意义上起作用,即它不是无效的语法,但就返回两个其他日期值之间的日期值而言,这些比较是破碎

答案 1 :(得分:2)

所以,发生的事情有点奇怪。 这里的转换有点令人困惑,但让我们深入研究它。

在这种情况下,

TRUNC(SYSDATE-1)被转换为VARCHAR2,并根据默认的NLS参数转换为昨天的日期。
今天是2016年4月18日,所以它只会返回字符串&#39; 17-APR-16&#39; (基于默认的NLS格式)。

接下来,你连接到这个字符串,&#34; time&#34; string - 00:00:00。
这构建了字符串&#39; 17-APR-16 00:00:00&#39; - 昨天午夜 这包含在&#34; To_date&#34;格式为&#39; DD-MON-YY HH24:MI:SS&#39;这使它成为一个实际的日期(数据DATE)。

构建的第二个日期是昨天的最后一分钟 - &#39; 17-APR-16 23:59:59&#39; ......

因此,您正在查找昨天在此查询中创建的所有记录。

由于&#34; TRUNC&#34;它有点令人困惑。日期返回日期,但串联到字符串会强制进行隐式转换。

如果您对此处的内容有更多疑问,请与我们联系。

P.S。我建议只使用日期重写查询,因为查询将失败并使用不同的NLS设置...