2011-09-01 35 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));