两个日期之间的Oracle SQL数据

Omn*_*ius 0 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')
Run Code Online (Sandbox Code Playgroud)

除非我将底线改为:否则这似乎不起作用:

AND CREATEDATE <=TO_DATE(TRUNC(SYSDATE) || ' 23:59:59', 'DD-MON-YY HH24:MI:SS')
Run Code Online (Sandbox Code Playgroud)

任何帮助理解此代码将不胜感激.

spe*_*593 5

谓词看起来比它们需要的更复杂.

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

   WHERE CREATEDATE >= TRUNC(SYSDATE-1)
     AND CREATEDATE <  TRUNC(SYSDATE)
Run Code Online (Sandbox Code Playgroud)

要在"普通英语"中解释这个SELECT语句返回的所有三个表达式:

 SELECT SYSDATE
      , TRUNC(SYSDATE)
      , TRUNC(SYSDATE-1)
   FROM DUAL
Run Code Online (Sandbox Code Playgroud)

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

  -------------------  -------------------  -------------------
  2016-04-16 13:59:26  2016-04-16 00:00:00  2016-04-15 00:00:00
Run Code Online (Sandbox Code Playgroud)

我们没有看到的是CREATEDATE的数据类型.显然,我们希望将其定义为DATE.但是如果你已经将它声明为VARCHAR并且以'16 -APR-2016 13:59:26'的格式存储字符串,那么"似乎不起作用",除非"你观察到的问题只是冰山一角.

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


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

 ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD' ;
Run Code Online (Sandbox Code Playgroud)

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

  • SYSDATE 将当前日期和时间作为DATE返回

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

  • TRUNC(<dateexpr>) 从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值转换为字符串时.

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

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