要允许超级用户/管理员登录我的系统,我正在运行(更大版本)此查询:
Select *
From mytable
Where (:id = 'Admin' Or :id = mytable.id);
如果我传递用户ID,我会获得该用户的所有数据;如果我传递字符串'Admin',我得所有数据。 这是有效的,因为Oracle的OR是short-circuit operator。
但是,如果我将'Admin'设为一个包常量并使用函数来获取它,就像这样
Select *
From mytable
Where (:id = mypackage.GetAdminConstant Or :id = mytable.id);
当我通过'Admin'时,我得到ORA-01722: invalid number
。
为什么在引入函数时OR会失去其短路方面?
答案 0 :(得分:6)
它不会失去短路方面。但SQL不是一种过程语言,并且不能保证多个谓词的评估顺序。
在C中,如果你写a || b
,你就知道会先评估a
,然后只在必要时评估b
。
在SQL中,如果您编写a OR b
,您只知道将首先评估a
或b
,并且将评估另一个表达式(至少在Oracle中)只在必要的时候。
查看两个查询的执行计划可能会给出评估顺序的一些指示,或者可能没有。
我猜想,在第一种情况下,Oracle可以看到第一个表达式对于每一行都具有相同的值,因此首先对其进行求值。当您更改为第二种情况时,Oracle现在会看到一个函数,每次计算时都会有不同的结果,因此它必须检查每一行,因此它会在执行函数调用之前尝试对列执行简单的相等性检查
我想知道如果你标记函数DETERMINISTIC会得到不同的结果,所以Oracle会知道它本质上是一个常数。
答案 1 :(得分:1)
最好使用2个绑定变量。
Select *
From mytable
Where (:admin = 'Admin' Or (:admin is null and :id = mytable.id));