51 votes

Déterminer Oracle null == null

Je souhaite effectuer une recherche dans une table de base de données sur une colonne nullable. Parfois, la valeur que je recherche est elle-même NULL. Puisque Null est égal à rien, même NULL, dire

where MYCOLUMN=SEARCHVALUE 

échouera. Pour l'instant, je dois recourir à

where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))

Y a-t-il une façon plus simple de le dire ?

(J'utilise Oracle si cela compte)

0 votes

Il est plutôt évident que NVL va "ralentir les choses", surtout pour les colonnes indexées.

76voto

Andy Lester Points 34051

Vous pouvez faire le truc IsNull ou NVL, mais cela ne fera qu'augmenter le travail du moteur. Vous appellerez des fonctions pour effectuer des conversions de colonnes dont les résultats devront ensuite être comparés.

Utilisez ce que vous avez

where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))

39voto

DCookie Points 22921

@Andy Lester affirme que la forme originale de la requête est plus efficace que l'utilisation de NVL. J'ai décidé de tester cette affirmation :

    SQL> DECLARE
      2    CURSOR B IS
      3       SELECT batch_id, equipment_id
      4         FROM batch;
      5    v_t1  NUMBER;
      6    v_t2  NUMBER;
      7    v_c1  NUMBER;
      8    v_c2  NUMBER;
      9    v_b   INTEGER;
     10  BEGIN
     11  -- Form 1 of the where clause
     12    v_t1 := dbms_utility.get_time;
     13    v_c1 := dbms_utility.get_cpu_time;
     14    FOR R IN B LOOP
     15       SELECT COUNT(*)
     16         INTO v_b
     17         FROM batch
     18        WHERE equipment_id = R.equipment_id OR (equipment_id IS NULL AND R.equipment_id IS NULL);
     19    END LOOP;
     20    v_t2 := dbms_utility.get_time;
     21    v_c2 := dbms_utility.get_cpu_time;
     22    dbms_output.put_line('For clause: WHERE equipment_id = R.equipment_id OR (equipment_id IS NULL AND R.equipment_id IS NULL)');
     23    dbms_output.put_line('CPU seconds used: '||(v_c2 - v_c1)/100);
     24    dbms_output.put_line('Elapsed time: '||(v_t2 - v_t1)/100);
     25  
     26  -- Form 2 of the where clause
     27    v_t1 := dbms_utility.get_time;
     28    v_c1 := dbms_utility.get_cpu_time;
     29    FOR R IN B LOOP
     30       SELECT COUNT(*)
     31         INTO v_b
     32         FROM batch
     33        WHERE NVL(equipment_id,'xxxx') = NVL(R.equipment_id,'xxxx');
     34    END LOOP;
     35    v_t2 := dbms_utility.get_time;
     36    v_c2 := dbms_utility.get_cpu_time;
     37    dbms_output.put_line('For clause: WHERE NVL(equipment_id,''xxxx'') = NVL(R.equipment_id,''xxxx'')');
     38    dbms_output.put_line('CPU seconds used: '||(v_c2 - v_c1)/100);
     39    dbms_output.put_line('Elapsed time: '||(v_t2 - v_t1)/100);
     40  END;
     41  /

    For clause: WHERE equipment_id = R.equipment_id OR (equipment_id IS NULL AND R.equipment_id IS NULL)
    CPU seconds used: 84.69
    Elapsed time: 84.8
    For clause: WHERE NVL(equipment_id,'xxxx') = NVL(R.equipment_id,'xxxx')
    CPU seconds used: 124
    Elapsed time: 124.01

    PL/SQL procedure successfully completed

    SQL> select count(*) from batch;

  COUNT(*)
----------
     20903

SQL> 

J'ai été assez surpris de découvrir à quel point Andy est correct. La solution NVL coûte près de 50 % de plus. Donc, même si un morceau de code n'a pas l'air aussi ordonné ou élégant qu'un autre, il peut être nettement plus efficace. J'ai exécuté cette procédure plusieurs fois, et les résultats étaient presque les mêmes à chaque fois. Félicitations à Andy...

1 votes

Joliment fait... Je vais peut-être devoir emprunter un peu de cela, juste pour le cadre de référence.

0 votes

Il faut également tenir compte du fait qu'en effectuant ces conversions, le moteur ne peut pas utiliser un index s'il y en a un sur la colonne. Par exemple, en faisant ceci : where ? = foo + 1 ne peut pas utiliser un index sur foo, mais where ? - 1 = foo peut utiliser l'index. Vous rencontrerez souvent ce problème avec les index de date.

0 votes

Voici le point de référence de Tom : asktom.oracle.com/pls/asktom/

14voto

Peter Meinl Points 1002

En Expert en architecture de base de données Oracle J'ai vu :

WHERE DECODE(MYCOLUMN, SEARCHVALUE, 1) = 1

13voto

Chris Shaffer Points 18066

Je ne sais pas si c'est plus simple, mais j'ai utilisé occasionnellement

WHERE ISNULL(MyColumn, -1) = ISNULL(SearchValue, -1)

Remplacer "-1" par une valeur valable pour le type de colonne, mais qui n'est pas susceptible d'être trouvée dans les données.

NOTE : J'utilise MS SQL, pas Oracle, donc je ne suis pas sûr que "ISNULL" soit valide.

2 votes

La fonction Oracle équivalente est NVL. Même syntaxe.

1 votes

En passant, vous pourriez faire la même chose avec Coalesce(MyColumn, -1) = Coalesce(SearchValue, -1).

5 votes

Je ne suis pas entièrement à l'aise avec les critères proposés pour la sélection de la valeur de remplacement NULL. Le critère "non susceptible d'être trouvé" est-il suffisant ? Que se passe-t-il lorsqu'une valeur "improbable" apparaît de part et d'autre du test d'égalité ? Est-il maintenant acceptable de faire correspondre un NULL avec une valeur "improbable" ?

8voto

JosephStyons Points 21187

Utilisez NVL pour remplacer null par une valeur fictive des deux côtés, comme dans :

WHERE NVL(MYCOLUMN,0) = NVL(SEARCHVALUE,0)

1 votes

Que se passe-t-il si mycolumn est null mais searchvalue est 0 ; ou vice versa ?

3 votes

Si 0 est une valeur qui peut se produire dans vos données ou dans la valeur de recherche, alors vous devez utiliser une valeur fictive différente. Si vous ne parvenez pas à trouver une valeur fictive appropriée, vous ne pouvez pas utiliser cette approche.

4 votes

Vous n'avez pas du tout besoin d'utiliser cette approche. Il n'y a aucune raison de comparer à des valeurs fictives lorsque vous pouvez comparer directement à des NULL réels.

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