【问题标题】:No short-circuit OR with an Oracle function?没有短路 OR 与 Oracle 功能?
【发布时间】:2011-11-08 15:25:08
【问题描述】:

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

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

如果我传递一个用户 ID,我会得到该用户的所有数据;如果我传递字符串 'Admin' 我得到 all 数据。 这是可行的,因为 Oracle 的 OR 是 short-circuit operator

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

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

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

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

【问题讨论】:

  • 并非如此。我能找到的文档说它 is 短路;这似乎是规则的一个例外,我想知道为什么。
  • :id 是什么(是绑定???),mypackage.GetAdminConstant 是什么类型?
  • 是的,:id 是一个绑定变量。 mypackage.GetAdminConstant 返回 Varchar2。

标签: sql oracle plsql short-circuiting


【解决方案1】:

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

在C语言中,如果你写a || b,你知道a会首先被评估,然后b只会在必要时被评估。

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

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

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

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

【讨论】:

  • 当我尝试直接访问常量 (schema.package.constant) 我得到MYCONSTANT is not a procedure or is undefined。我做错了什么?
  • 啊,我看到我上面链接的文档是针对 PL/SQL,而不是 SQL。我检查了我的执行计划:你是对的,它会在两个查询之间切换评估顺序。不幸。
  • @Brian -- 抱歉,看起来实际上不可能在 SQL 中直接使用包常量。从我的回答中删除了该建议。
  • 那太糟糕了。将函数标记为 DETERMINISTIC 也不行。我想我必须找到一个不同的解决方案。
  • 怎么样:to_char(:id)=mypackage.GetAdminConstant
【解决方案2】:

最好使用 2 个绑定变量。

Select *
  From mytable
 Where (:admin = 'Admin' Or (:admin is null and :id = mytable.id));

【讨论】:

    猜你喜欢
    • 2016-10-24
    • 2011-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-28
    • 2015-11-19
    • 1970-01-01
    • 2019-05-25
    相关资源
    最近更新 更多