Firebird Documentation Index → Guida sull'uso di NULL nel linguaggio SQL di Firebird → Controllare per NULL e per l'eguaglianza nella pratica |
Questa sezione contiene alcuni suggerimenti pratici ed esempi che
possono essere utili avendo a che fare con i NULL
.
Riguarda i casi in cui si vuol verificare lo stato di
NULL
di un campo o l'(in)uguaglianza fra due cose
qualora possano essere implicati dei NULL
.
Frequentemente non si ha bisogno di prendere misure particolari
per i campi o le variabili che potrebbero essere
NULL
. Ad esempio, facendo come segue:
select * from Clienti where Comune = 'Verona'
molto probabilmente non si vogliono elencati i clienti per i quali la città non risulta specificata. Allo stesso modo:
if (Eta >= 18) then PotestVotare = 'Si'
non include le persone di età sconosciuta, quindi è difendibile, ed include le persone di età sconosciuta, ed è pure questo difendibile. Ma:
if (Eta >= 18) then PotestVotare = 'Si'; else PotestVotare = 'No';
sembra meno giustificabile: se non si conosce l'età di una persona, non si può esplicitamente negargli il diritto di voto. Ancora peggio, è far questo:
if (Eta < 18) then PotestVotare = 'No'; else PotestVotare = 'Si';
che non può avere lo stesso effetto del precedente esempio. Se alcuni di cui non si sa l'età sono in realtà minorenni (Eta < 18), gli si permette di votare!
Il miglior metodo in questo caso è controllare esplicitamente se
vale NULL
:
if (Eta is null) then PotestVotare = '??'; else if (Eta >= 18) then PotestVotare = 'Si'; else PotestVotare = 'No';
Poichè si hanno più di due possibilità, è più elegante usare la sintassi dello statement CASE, che è disponibile a partire da Firebird 1.5 e successivi:
PotestVotare = case when Eta is null then '??' when Eta >= 18 then 'Si' else 'No' end;
O, ancora meglio:
PotestVotare = case when Eta >= 18 then 'Si' when Eta < 18 then 'No' else '??' end;
Quando si vuole verificare se due campi o variabili sono identici
e li si vuol considerare uguali anche se sono entrambi
NULL
, il modo per farlo dipende dalla versione di
Firebird che si sta' usando.
In Firebird 2 e succesivi, si confronta per la non uguaglianza dei valori con DISTINCT. Questo è già stato visto in precedenza, ma qui lo rivediamo brevemente. Due espressioni sono considerate:
DISTINCT se hanno valori diversi oppure
una delle due è NULL
e l'altra no;
NOT DISTINCT se hanno lo stesso valore
oppure se entrambe sono NULL
.
[NOT] DISTINCT riporta sempre o
true
o false
, mai
NULL
o altri valori. Examples:
if (A is distinct from B) then...
if (Cliente1 is not distinct from Cliente2) then...
Chi non è interessato ai metodi pre-Firebird 2, può saltare le seguenti sezioni.
Queste versioni non supportano l'uso di DISTINCT. Di conseguenza i test sono un po' più complicati e ci sono alcuni trabocchetti da evitare.
Il test di uguaglianza corretto per le versioni in esame è:
if (A = B or A is null and B is null) then...
oppure, esplicitando le precedenze degli operatori:
if ((A = B) or (A is null and B is null)) then...
È necessario avvertire di una cosa: se esattamente uno solo fra
A e B è proprio NULL
, l'espressione diventa
NULL
, non falsa! Questo è giusto, per quanto
abbiamo visto prima, in uno statement di if
, e si
potrebbe anche aggiungere perfino un clausola else
che può essere eseguita nel caso in cui A e B non sono uguali (incluso
il caso in cui uno dei due è NULL
e l'altro
no):
if (A = B or A is null and B is null) then ...cose da fare se A è uguale a B... else ...cose da fare se A è diverso da B...
Ma bisogna evitare come la peste la brillante idea di invertire le espressioni e di usarle come un test di ineguaglianza:
/* Da evitare! */ if (not(A = B or A is null and B is null)) then ...cose da fare se A non è uguale a B...
Il codice qui sopra funziona correttamente se A e B sono
entrambi NULL
o entrambi diversi da
NULL
. Ma nel caso in cui uno solo dei due sia
NULL
non entra nella parte
then
perchè il test vale NULL, invece che essere
valutato a vero come si potrebbe essere indotti erroneamente a
pensare.
Volendo eseguire un codice se e solo se A e B sono differenti,
si può usare una delle espressioni corrette viste sopra mettendo uno
statement innocuo nella clausola then
. A partire
dalla 1.5 si possono usare anche blocchi begin..end
vuoti. In alternativa si può usare una espressione più lunga come
questa:
/* Questo è un corretto test per diseguaglianza: */ if (A <> B or A is null and B is not null or A is not null and B is null) then...
Ricordare che questo è necessario dsolo nelle versioni
precedenti alla 2.0 di Firebird. A partire dalla 2 in poi, il test di
disuguaglianza si fa semplicemente con «if (A is distinct
from B)
».
Tabella 11. Verificare la (dis)uguaglianza di A e B in versioni differenti di Firebird
Tipo di controllo | Versione di Firebird | |
---|---|---|
<= 1.5.x | >= 2.0 | |
Uguaglianza |
A = B or A is null and B is null |
A is not distinct from B |
Disuguaglianza |
A <> B or A is null and B is not null or A is not null and B is null |
A is distinct from B |
Tenere ben presente che in Firebird 1.5.x e precedenti:
il test d'uguaglianza riporta NULL
se
uno solo degli operandi è NULL
;
il test di disuguaglianza riporta NULL
se entrambi gli operandi sono NULL
.
In un contesto di tipo IF o
WHERE, questi risultati NULL
si comprtano come false
– che andrebbe bene in
generale. Ma bisogna fare attenzione che invertendo con
NOT() da' ilmedesimo risultato
NULL
, e non
«true
». Inoltre se si usano i
confronti della versione 1.5 e precedenti con un vincolo di
CHECK in Firebird 2 o successivi, leggere
attentamente la sezione Vincoli
di controllo (CHECK constraints), se non
l'avete già fatto.
Molte operazioni di JOIN sono costituite
da uguaglianze su campi di diverse tabelle, ed usano l'operatore
«=
». Questo elimina tutte le coppie
NULL
-NULL
. Per far
corrispondere fra loro due NULL
, selezionare il
test di uguaglianza adatto per la versione di Firebird usata dalla
tabella sopra.
Nei trigger è spesso utile sapere se un certo campo è stato
modificato (compresa la trasformazione da NULL
a
non-NULL
o viceversa) oppure è rimasto identico
(compreso il mantenere lo stato di NULL
). Questo
non è altro che un caso speciale del controllo di (dis)uguaglianza di
due campi.
In Firebird 2 e successivi si usa questo codice:
if (New.Valore is not distinct from Old.Valore) then ...il Valore non è cambiato... else ...il Valore è cambiato...
E nelle precedenti versioni:
if (New.Valore = Old.Valore or New.Valore is null and Old.Valore is null) then ...il campo Valore è rimasto uguale... else ...il campo Valore è cambiato...
Firebird Documentation Index → Guida sull'uso di NULL nel linguaggio SQL di Firebird → Controllare per NULL e per l'eguaglianza nella pratica |