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'Admin'を渡すと取得します。

関数を導入すると、ORが短絡の側面を失うのはなぜですか?

4

2 に答える 2

6

短絡面を失うことはありません。ただし、SQLは手続き型言語ではなく、複数の述語の評価の順序を保証するものではありません。

Cでは、と書くと、それが最初に評価され、次に必要な場合にのみ評価されるa || bことがわかります。ab

SQLでは、を書くと、またはが最初に評価され、他の式(少なくともOracleでは)が必要な場合にのみ評価されることa OR bがわかります。ab

2つのクエリの実行プランを見ると、評価の順序がわかる場合とそうでない場合があります。

最初のケースでは、Oracleは最初の式がすべての行で同じ値を持つことを確認できるので、最初にそれを評価すると思います。2番目のケースに変更すると、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 に答える