Je souhaite rechercher une table de base de données sur une colonne nullable. Parfois, la valeur que je recherche est elle-même NULL. Depuis Null est égal à rien, même NULL, en disant
where MYCOLUMN=SEARCHVALUE
va échouer. En ce moment je dois recourir à
where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))
Y a-t-il un moyen plus simple de dire cela?
(J'utilise Oracle si ça compte)
Vous pouvez effectuer les opérations IsNull ou NVL, mais cela ne fera que faire en sorte que le moteur travaille davantage. Vous allez appeler des fonctions pour effectuer des conversions de colonnes qui doivent ensuite comparer les résultats.
Utilisez ce que vous avez
where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))
@Andy Lester affirme que la forme originale de la requête est plus efficace que d'utiliser 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é un peu surpris de découvrir à quel point Andy est correct. La solution NVL coûte presque 50% de plus. Ainsi, même si un élément de code peut ne pas sembler aussi propre et élégant qu'un autre, il peut être considérablement plus efficace. J'ai exécuté cette procédure plusieurs fois et les résultats étaient presque les mêmes à chaque fois. Bravo à Andy ...
Dans Expert Oracle Database Architecture J'ai vu:
WHERE DECODE(MYCOLUMN, SEARCHVALUE, 1) = 1
Je ne sais pas si c'est plus simple, mais j'ai parfois utilisé
WHERE ISNULL(MyColumn, -1) = ISNULL(SearchValue, -1)
Remplacer "-1" par une valeur valide pour le type de colonne, mais également non susceptible d'être trouvée dans les données.
NOTE: J'utilise MS SQL, pas Oracle, donc je ne sais pas si "ISNULL" est valide.
Utilisez NVL pour remplacer null par une valeur fictive des deux côtés, comme dans:
WHERE NVL(MYCOLUMN,0) = NVL(SEARCHVALUE,0)
Une autre alternative, probablement optimale du point de vue de la requête exécutée, et ne sera utile que si vous effectuez un type de génération de requête est de générer la requête exacte dont vous avez besoin en fonction de la valeur de recherche.
Le pseudocode suit.
if (SEARCHVALUE IS NULL) {
condition = 'MYCOLUMN IS NULL'
} else {
condition = 'MYCOLUMN=SEARCHVALUE'
}
runQuery(query,condition)
Si une valeur hors bande est possible:
where coalesce(mycolumn, 'out-of-band')
= coalesce(searchvalue, 'out-of-band')
Cela peut également faire le travail dans Oracle.
WHERE MYCOLUMN || 'X' = SEARCHVALUE || 'X'
Dans certaines situations, il bat le test IS NULL avec le OU.
J'ai également été surpris que DECODE vous permette de comparer NULL à NULL.
WITH
TEST AS
(
SELECT NULL A FROM DUAL
)
SELECT DECODE (A, NULL, 'NULL IS EQUAL', 'NULL IS NOT EQUAL')
FROM TEST
Essayer
WHERE NVL(mycolumn,'NULL') = NVL(searchvalue,'NULL')
C'est une situation dans laquelle nous nous trouvons souvent avec nos fonctions Oracle qui génèrent des rapports. Nous voulons permettre aux utilisateurs d'entrer une valeur pour limiter les résultats ou la laisser vide pour renvoyer tous les enregistrements. C'est ce que j'ai utilisé et cela a bien fonctionné pour nous.
WHERE rte_pending.ltr_rte_id = prte_id
OR ((rte_pending.ltr_rte_id IS NULL OR rte_pending.ltr_rte_id IS NOT NULL)
AND prte_id IS NULL)
Je penserais que ce que tu as est OK. Vous pourriez peut-être utiliser:
where NVL(MYCOLUMN, '') = NVL(SEARCHVALUE, '')