2011-09-01 7 views
1

Pour autoriser un Super User/Admin pour me connecter à mon système, je suis en cours d'exécution (une version plus grande) cette requête:Pas de court-circuit OU avec une fonction Oracle?

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

Si je passe un nom d'utilisateur, je reçois toutes les données pour cet utilisateur; si je passe la chaîne 'Admin' j'obtiens tous les données. Cela fonctionne parce que Oracle est un short-circuit operator.

Cependant, si je fais « Admin » une constante de l'emballage et l'obtenir avec une fonction, comme celui-ci

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

je reçois ORA-01722: invalid number quand je passe « Admin ».

Pourquoi OU perdre son aspect de court-circuit lorsque j'introduis une fonction?

+0

double possible de [SGBD modernes comprennent Est-ce l'évaluation booléenne court-circuit?] (Http://stackoverflow.com/questions/6960767/do-modern-dbms-include-short-circuit-boolean-evaluation) –

+0

Pas vraiment. La documentation que je peux trouver indique que c'est * un court-circuit; cela semble être une exception à la règle, et j'aimerais savoir pourquoi. –

+0

Qu'est-ce que ': id' (est-ce un bind ???) et de quel type est' mypackage.GetAdminConstant'? –

Répondre

6

Il ne perd pas l'aspect court-circuit. Mais SQL n'est pas un langage procédural, et il n'y a aucune garantie de l'ordre d'évaluation de plusieurs prédicats. En C, si vous écrivez a || b, vous savez que a sera évalué en premier, alors b sera évalué seulement si nécessaire.

Dans SQL, si vous écrivez a OR b, vous savez seulement que ce soit a ou b seront évaluées en premier lieu, et que l'autre expression (au moins dans Oracle) ne sera évaluée que si nécessaire.

Si vous observez le plan d'exécution des deux requêtes, cela peut donner une indication de l'ordre d'évaluation, mais il se peut que cela ne le soit pas.

Je suppose que, dans votre premier cas, Oracle peut voir que la première expression aura la même valeur pour chaque ligne, donc l'évalue en premier. Lorsque vous passez au second cas, Oracle voit maintenant une fonction qui pourrait avoir des résultats différents à chaque fois qu'il est évalué, il devra donc vérifier chaque ligne, donc il essaie de faire la vérification d'égalité simple sur une colonne avant de faire l'appel de fonction .

Je me demande si vous obtiendriez des résultats différents si vous avez marqué la fonction DETERMINISTIC afin qu'Oracle sache qu'il s'agit essentiellement d'une constante.

+0

Lorsque j'essaie d'accéder directement à la constante (schema.package.constant), j'obtiens 'MYCONSTANT n'est pas une procédure ou est undefined'. Qu'est-ce que je fais mal? –

+0

Ah, je vois que la documentation à laquelle je suis lié est pour PL/SQL, pas SQL. Et j'ai vérifié mon plan d'exécution: vous aviez raison, il bascule l'ordre d'évaluation entre les deux requêtes. Malheureux. –

+0

@Brian - désolé, il semble qu'il ne soit pas possible d'utiliser directement une constante de paquet dans SQL. Retiré cette suggestion de ma réponse. –

1

Mieux utiliser 2 variables de liaison.

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