1

为了允许超级用户/管理员登录到我的系统,我正在运行(更大版本的)这个查询:

Select *
  From mytable
 Where (:id = 'Admin' Or :id = mytable.id);

如果我传递一个用户 ID,我将获得该用户的所有数据;如果我传递字符串'Admin',我会得到所有数据。这是因为 Oracle 的 OR 是短路运算符

但是,如果我将“Admin”设为包常量并使用函数获取它,就像这样

Select *
  From mytable
 Where (:id = mypackage.GetAdminConstant Or :id = mytable.id);

ORA-01722: invalid number当我通过“管理员”时,我得到了。

当我引入一个函数时,为什么 OR 会失去它的短路特性?

4

2 回答 2

6

它不会失去短路方面。但是 SQL 不是过程语言,不能保证多个谓词的求值顺序。

在 C 中,如果您编写a || b,您知道a将首先评估,然后b仅在必要时评估。

在 SQL 中,如果你写a OR b,你只知道要么 要么ab首先被评估,而另一个表达式(至少在 Oracle 中)只有在必要时才会被评估。

查看两个查询的执行计划可能会给出评估顺序的一些指示,也可能不会。

我猜想,在您的第一种情况下,Oracle 可以看到第一个表达式对于每一行都具有相同的值,因此首先对其进行评估。当您更改为第二种情况时,Oracle 现在会看到一个函数,每次评估它时可能会产生不同的结果,因此它必须检查每一行,因此它会在执行函数调用之前尝试对列进行简单的相等性检查.

我想知道如果你标记函数 DETERMINISTIC 是否会得到不同的结果,这样 Oracle 就会知道它本质上是一个常数。

于 2011-09-01T18:44:15.440 回答
1

最好使用 2 个绑定变量。

Select *
  From mytable
 Where (:admin = 'Admin' Or (:admin is null and :id = mytable.id));
于 2011-09-05T11:59:05.597 回答