首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >systimestamp和sysdate的奇怪行为

systimestamp和sysdate的奇怪行为
EN

Stack Overflow用户
提问于 2020-06-17 20:22:42
回答 2查看 382关注 0票数 2

今天我遇到了一个我无法解释的情况,我希望你能。

归根结底是这样的:

假设function sleep() return number;循环10秒,然后返回1。

类似的sql查询

代码语言:javascript
复制
SELECT systimestamp s1, sleep(), systimestamp s2 from dual;

将为s1和s2生成两个相同的值。所以这是某种程度的优化。

PLSQL-块

代码语言:javascript
复制
a_timestamp := systimestamp + 5sec;
IF systimestamp < a_timestamp and sleep() = 1 and systimestamp > a_timestamp THEN 
  [...] 
END IF;

将计算为true,因为表达式从左到右得到求值,而且由于睡眠(),第二个systimestamp比第一个大10秒,a_timestamp介于两者之间。+5秒的语法是伪代码,但是请原谅我。因此,在这里,systimestamp没有被优化。

但现在它变得古怪了:

代码语言:javascript
复制
IF systimestamp between systimestamp and systimestamp THEN [...]

总是假的,但是

代码语言:javascript
复制
IF systimestamp + 0 between systimestamp + 0 and systimestamp + 0 THEN [...]

永远都是真的。

为什么?我很困惑..。

这种情况也发生在sysdate上。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-06-18 11:57:47

当你这样做时:

代码语言:javascript
复制
if systimestamp between systimestamp and systimestamp then

对不确定的systimestamp调用只进行三次评估,每次得到的结果略有不同。

你可以看到同样的效果

代码语言:javascript
复制
if systimestamp >= systimestamp then

它也总是返回false。

不过,也不总是这样。如果服务器足够快,并且/或它所在的平台的精度很低--足够精确到时间戳小数秒(例如,在Windows上,我认为它仍然将精度限制在毫秒),那么所有这些调用在某些时候或大部分时间仍然可以得到相同的值。

SQL中的情况有些不同;作为一个等价的:

代码语言:javascript
复制
select *
from dual
where systimestamp between systimestamp and systimestamp;

将始终返回一行,因此条件始终为真。那是文件中明确提到

所有返回当前系统日期时间信息的datetime函数,例如SYSDATE、SYSTIMESTAMP、CURRENT_TIMESTAMP等,都会为每个SQL语句计算一次,而不管它们在该语句中引用了多少次。

PL/SQL中没有这样的限制/优化(取决于您如何看待它)。当您使用between 上面确实写着

A和b之间表达式x的值被定义为与表达式(x>=a)和(x<=b)的值相同。表达式x将只计算一次。

和SQL引用还提到

在SQL中,可能会对expr1进行多次评估。如果中间表达式出现在PL/SQL中,则保证只计算expr1一次。

但是它并没有提到跳过a和b(或expr2或expr3)的计算,甚至对于PL/SQL中的系统日期时间函数也是如此。

因此,您的between中的所有三个表达式都将被计算,它将对systimestamp进行三个单独的调用,它们(通常)都会得到稍微不同的结果。你实际上得到的结果是:

代码语言:javascript
复制
if initial_time between initial_time + 1 microsecond and initial_time + 2 microseconds then

或者换个说法

代码语言:javascript
复制
if (initial_time >= initial_time + 1 microsecond) and (initial_time <= initial_time + 2 microseconds) then

虽然(initial_time <= initial_time + 2 microseconds)总是正确的,但是(initial_time >= initial_time + 1 microsecond)必须是假的--除非对于平台/服务器/调用,第一个和第三个评估之间的间隔实际上是零。当条件为零时,计算结果为true;其余时间,当存在任何可测量的延迟时,它将计算为false。

其他示例都以删除小数秒的方式操作时间戳,方法是将部分或全部结果转换为日期,如@Connor所示(我在注释中提到了这一点)。这与你的核心问题(为什么if systimestamp between systimestamp and systimestamp then (通常)是假的)并没有什么关系。

票数 1
EN

Stack Overflow用户

发布于 2020-06-18 03:58:02

如果将数字添加到时间戳中,则不会得到timestamp...you获取日期。因此,您已经去掉了小数秒部分,因此看起来它们应该相等的比较可能不是。

代码语言:javascript
复制
SQL> select systimestamp, systimestamp+0 from dual;

SYSTIMESTAMP                                                                SYSTIMESTAMP+0
--------------------------------------------------------------------------- -------------------
18-JUN-20 11.57.28.350000 AM +08:00                                         18/06/2020 11:57:28

SQL> select * from dual where systimestamp > sysdate;

D
-
X

如果要将天数等添加到时间戳中,请使用间隔数据类型而不是数字。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62437737

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档