我正在查看一些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')
理解此代码的任何帮助都将受到赞赏。
答案 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设置...