6 votes

Pourquoi "Where 1 <> 1" dans une requête renverrait-il toutes les lignes ?

Je suis tombé sur une requête dans une application dont j'ai hérité qui ressemble à ceci :

Select *
From foo
where
    1 <> 1

Lorsque je l'analyse, il ne devrait rien retourner ( 1 <> 1 devrait être évalué à faux, à droite). Cependant (du moins sur ma machine Oracle), il revient avec une liste complète de tout ce qui se trouve dans le fichier foo . Lorsque j'essaie la même chose dans MSAccess/Jet et MSSQL, j'obtiens le comportement que j'attends. Pourquoi est-ce différent pour Oracle (et pourquoi le développeur original voudrait-il faire cela) ?

Note : J'ai vu une certaine superstition à propos des avantages et des inconvénients de l'utilisation de "where 1 = 1", qui provoque des balayages complets de la table ; mais je ne pense pas que c'était l'intention du développeur original.

Petite mise à jour :
Dans ce cas foo est une vue. Lorsque j'essaie la même chose sur une table réelle, j'obtiens ce à quoi je m'attends (aucune ligne).

Mise à jour 2 :
J'ai suivi le code plus loin dans le terrier du lapin et j'ai déterminé que tout ce qu'il fait est d'essayer de saisir les noms des champs/colonnes. Je ne comprends toujours pas pourquoi il renvoie l'ensemble complet d'enregistrements, mais uniquement sur les vues.

Littéralement, il construit la requête dans une chaîne et la transmet à une autre fonction pour qu'elle l'exécute sans la modifier.

'VB6
strSQL = "SELECT * FROM " & strTableName & " WHERE 1 <> 1"

Dans ce cas, strTableName contient le nom d'une vue.

Mise à jour 3 :
Pour référence, voici l'une des vues avec lesquelles j'ai des problèmes (J'ai changé les noms des champs/tables/schémas)

CREATE OR REPLACE FORCE VIEW scott.foo (field1,
                                        field2,
                                        field4,
                                        field5,
                                        field12,
                                        field8,
                                        field6,
                                        field7,
                                        field16,
                                        field11,
                                        field13,
                                        field14,
                                        field15,
                                        field17
                                       )
AS
   SELECT   bar.field1,
            bar.field2,
            DECODE
               (yadda.field9, NULL, 'N',
                DECODE (yadda.field3, NULL, 'Y', 'N')
               ) AS field4,
            bar.field5,
            snafu.field6,
            DECODE
                (snafu.field6,
                 NULL,
                bar.field8,
                   bar.field8
                 - snafu.field6
                ) AS field7,
            DECODE
               (yadda.field10,
                NULL,
            bar.field12,
                yadda.field10
               ) AS field11,
            DECODE
               (SIGN (  yadda.field10 - bar.field12),
                NULL, 'N', 1, 'N', 0, 'N', -1, 'Y'
               ) AS field13,
            bar.field14,
            ADD_MONTHS
               (DECODE (yadda.field10, NULL, bar.field12, yadda.field10
                       ),
                bar.field14 * 12
               ) AS field15,
       FROM clbuttic,
            bar,
            yadda,
            snafu
      WHERE clbuttic.asset_type = bar.asset_type
        AND bar.field16 = yadda.field9(+)
        AND bar.field1 = snafu.field1(+)
        AND (bar.field17 IS NULL)
   ;

Ajout de Order By 1 (ou un nom de colonne dans le select on foo) semble convaincre Oracle de me rendre l'ensemble vide. C'est une solution à long terme, mais pas à court terme (changer le code et le redéployer est un grand PITA). J'espère qu'il y a un paramètre peu connu du côté de la base de données ou quelque chose de mal dans la vue qui est la cause de ce comportement étrange.

15voto

Beska Points 6717

Ok... je ne comprends pas pourquoi cela se produit dans Oracle. Cependant, je peux vous dire pourquoi c'est souvent utilisé dans d'autres bases de données : quand la personne veut que les colonnes soient retournées, mais pas les valeurs. (Par exemple, pour créer un schéma pour une nouvelle table).

7voto

Paul Tomblin Points 83687

Oracle ne fait pas ça pour moi :

SQL*Plus: Release 10.2.0.1.0 - Production on Thu Mar 19 13:36:20 2009

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Connected to:
Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production

SQL> select * from wrkr where 1 <> 1;

no rows selected

SQL> select count(*) from wrkr;

  COUNT(*)
----------
        88

Edit : Il n'y a rien d'intrinsèque aux vues, non plus :

SQL> create view foo as select * from wrkr;

View created.

SQL> select count(*) from foo;

  COUNT(*)
----------
        88

SQL> select * from foo where 1 <> 1;

no rows selected

5voto

Mehrdad Afshari Points 204872

Lorsque vous souhaitez générer dynamiquement un WHERE clause. De cette façon, vous pouvez simplement ajouter des OR [another-condition] et le faire fonctionner sans vérifier si la condition est la première ou non.

5voto

wip Points 319

Cela ressemble vraiment à un bogue dans le code de fusion des vues de l'optimiseur Oracle. Je parie que vous ne rencontrez ce problème qu'avec des vues qui contiennent des jointures externes. Votre site ORDER BY résout le problème, car il force pratiquement un NO_MERGE sur la vue.

Je ne mettrais pas non plus un ORDER BY ou un NO_MERGE à l'intérieur de la vue, car (selon le volume de vos données) cela pourrait dégrader les performances des autres requêtes qui utilisent la vue. Vous devriez mettre un indice no_merge dans la requête externe :

Select /*+ NO_MERGE(foo) */ *
From foo
where
    1 <> 1

Vous devez également envoyer un SR au support Oracle, car il s'agit bien d'un bogue. Cette requête ne devrait jamais renvoyer d'enregistrements, quelle que soit la nature de la sélection ou la complexité de son contenu. Jamais, jamais.

Je n'ai pas pu le reproduire, donc c'est probablement corrigé dans la version que j'utilise. Quelle est la version de la base de données que vous utilisez ?

3voto

Tony Andrews Points 67363

Pourquoi utiliser WHERE 1<>1 ?

Le seul endroit où je l'ai vu utilisé, ou même utilisé moi-même, est un moyen rapide de copier la structure d'un tableau sans copier le contenu :

create table foo2
as select * from foo where 1 <> 1;

(sauf que j'utilise toujours != plutôt que <> - ce que je ne devrais vraiment pas faire (voir le commentaire de Bill))

Bug apparent d'Oracle

Si vous avez un cas où vous pouvez clairement démontrer qu'Oracle renvoie des lignes dans SQL Plus lorsque vous exécutez "select * from my_view where 1<>1", alors vous devriez contacter le support Oracle (ou demander à la personne autorisée dans votre entreprise de le faire) : cela indiquerait un problème important. bug . Bien sûr, si vous utilisez une ancienne version d'Oracle, ils vous diront probablement de la mettre à jour !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X