2011-09-01 57 views
1

要允许超级用户/管理员登录到我的系统,我运行(一台放大版)这个查询:没有短路或与Oracle功能?

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

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

但是,如果我做“管理”一揽子不变,并用功能得到它,这样

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

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

为什么OR引入功能时会失去短路方面?

+0

的可能重复[做现代DBMS包括短路布尔评价?(http://stackoverflow.com/questions/6960767/do-modern-dbms-include-short-circuit-boolean-evaluation) –

+0

不是。我可以找到的文件说它*是*短路;这似乎是一个例外的规则,我想知道为什么。 –

+0

什么是':id'(是一个绑定???),什么类型是'mypackage.GetAdminConstant'? –

回答

6

它不会损失短路方面。但是SQL不是过程语言,也不能保证多个谓词的评估顺序。

在C,如果你写a || b,你知道a将先进行计算,然后b将只在必要时进行评估。

在SQL中,如果写a OR b,你只知道,要么ab将被首先计算,并且所述其它表达(至少在甲骨文)将只在必要时进行评估。

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

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

我想知道如果您标记了DETERMINISTIC函数,您是否会得到不同的结果,以便Oracle知道它基本上是一个常量。

+0

当我尝试直接访问常量(schema.package.constant)时,我得到'MYCONSTANT不是一个过程或者是未定义的'。我究竟做错了什么? –

+0

啊,我看到我上面链接到的文档是用于PL/SQL,而不是SQL。我检查了我的执行计划:您是对的,它会在两个查询之间切换评估顺序。不幸的。 –

+0

@Brian - 抱歉,看起来实际上不可能在SQL中直接使用包常量。从我的回答中删除了该建议。 –

1

更好地使用2个绑定变量。

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