| 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 |