没有短路 OR 与 Oracle 功能?

发布于 2024-12-02 16:13:56 字数 600 浏览 5 评论 0原文

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

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);

当我传递“Admin”时,我会得到ORA-01722:无效数字

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

To allow an Super User/Admin to log in to my system, I am running (a larger version of) this query:

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

If I pass a user id I get all the data for that user; if I pass the string 'Admin' I get all the data.
This works because Oracle's OR is a short-circuit operator.

However, if I make 'Admin' a package constant and get it with a function, like this

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

I get ORA-01722: invalid number when I pass 'Admin'.

Why does OR lose its short-circuit aspect when I introduce a function?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

等风来 2024-12-09 16:13:56

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

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

在 SQL 中,如果您编写 a OR b,您只知道 ab 将首先被计算,而另一个表达式 (至少在 Oracle 中)仅在必要时才进行评估。

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

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

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

It doesn't lose the short-circuit aspect. But SQL is not a procedural language, and there is no guarantee of the order of evaluation of multiple predicates.

In C, if you write a || b, you know that a will be evaluated first, then b will be evaluated only if necessary.

In SQL, if you write a OR b, you know only that either a or b will be evaluated first, and that the other expression (at least in Oracle) will be evaluated only if necessary.

Looking at the execution plan for the two queries may give some indication of the order of evaluation, or it may not.

I would guess that, in your first case, Oracle can see that the first expression will have the same value for every row, so evaluates it first. When you change to the second case, Oracle now sees a function that could have different results each time it is evaluated, so it will have to check each row, so it tries to do the simple equality check on a column before doing the function call.

I wonder if you would get different results if you marked the function DETERMINISTIC so Oracle would know that it is essentially a constant.

远山浅 2024-12-09 16:13:56

最好使用 2 个绑定变量。

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

Better use 2 bind variables.

Select *
  From mytable
 Where (:admin = 'Admin' Or (:admin is null and :id = mytable.id));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文