Oracle systimestamp和sysdate的奇怪行为

Oracle systimestamp和sysdate的奇怪行为,oracle,plsql,oracle18c,Oracle,Plsql,Oracle18c,今天我遇到了一个我无法解释的情况,我希望你能解释 归结起来就是: 假设函数sleep()返回数字循环10秒,然后返回1 类似sql的查询 SELECT systimestamp s1, sleep(), systimestamp s2 from dual; 将导致s1和s2的两个相同值。所以这有点优化了 带有 a_timestamp := systimestamp + 5sec; IF systimestamp < a_timestamp and sleep() = 1 and syst

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

归结起来就是:

假设
函数sleep()返回数字循环10秒,然后返回1

类似sql的查询

SELECT systimestamp s1, sleep(), systimestamp s2 from dual;
将导致s1和s2的两个相同值。所以这有点优化了

带有

a_timestamp := systimestamp + 5sec;
IF systimestamp < a_timestamp and sleep() = 1 and systimestamp > a_timestamp THEN 
  [...] 
END IF;
总是错误的,但是

IF systimestamp + 0 between systimestamp + 0 and systimestamp + 0 THEN [...]
这永远是真的

为什么??我很困惑


sysdate也会发生这种情况

如果在时间戳中添加一个数字,则不会得到时间戳…而是得到一个日期。因此,您删去了分数秒部分,因此看起来应该相等的比较可能不相等

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
如果要在时间戳中添加天数等,请使用间隔数据类型,而不是数字。

执行此操作时:

if systimestamp between systimestamp and systimestamp then
非确定性的
systimestamp
调用只被评估了三次,每次得到的结果都略有不同

你可以看到同样的效果

if systimestamp >= systimestamp then
它也总是返回false

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

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

select *
from dual
where systimestamp between systimestamp and systimestamp;
将始终返回一行,因此条件始终为true。即:

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

PL/SQL中没有这样的限制/优化(取决于您如何看待它)。在
之间使用
时:


表达式x在a和b之间的值被定义为与表达式(x>=a)和(x=初始_时间+1微秒)和(初始_时间?唯一得到false的方法是使用
systimestamp介于systimestamp+0和systimestamp+0之间的值
(而不是
systtimestamp+0介于…
)。当数据类型更改时,这是预期的(除非您非常幸运,而且分数秒恰好为零)。否则它会变成真的。你能重现你在小提琴中看到的吗?嗨,亚历克斯,你是对的。我交换了结果。没有添加,结果总是错误的:我有18c,我测试了它,我在这两种情况下都是真的。我很确定Oracle编译器进行了优化,并且systimestamp和systimestamp+0都只计算了一次,所以在这两种情况都是正确的。@Obenland-您的版本中的第三个和第四个块是预期的,同样是因为数据类型的更改。但是,第一个块很有趣。如果它分别三次评估systimestamp,那么在速度足够快且精度较低(毫秒)的系统上仍然可能是正确的,但即使这样,也可能不总是。@Vladimir.V.Bvn-SQL编译器会进行这种优化;PL/SQL编译器不会。谢谢您的回答!
select *
from dual
where systimestamp between systimestamp and systimestamp;
if initial_time between initial_time + 1 microsecond and initial_time + 2 microseconds then
if (initial_time >= initial_time + 1 microsecond) and (initial_time <= initial_time + 2 microseconds) then