Firebird Documentation IndexGuida sull'uso di NULL nel linguaggio SQL di Firebird → Controllare per NULL e per l'eguaglianza nella pratica
Firebird Home Firebird Home Indietro: Modifica delle tabelle piene di datiFirebird Documentation IndexRisali: Guida sull'uso di NULL nel linguaggio SQL di FirebirdAvanti: Sommario

Controllare per NULL e per l'eguaglianza nella pratica

Come controllare se ci sono NULL
Test di uguaglianza e confronti
Determinare se un campo è cambiato

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.

Come controllare se ci sono 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;

Test di uguaglianza e confronti

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.

Firebird 2.0 e successivi

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.

Versioni precedenti alla 2

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)».

Riassunto sui controlli di (dis)uguaglianza

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.

Suggerimento

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.

Determinare se un campo è cambiato

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...
Indietro: Modifica delle tabelle piene di datiFirebird Documentation IndexRisali: Guida sull'uso di NULL nel linguaggio SQL di FirebirdAvanti: Sommario
Firebird Documentation IndexGuida sull'uso di NULL nel linguaggio SQL di Firebird → Controllare per NULL e per l'eguaglianza nella pratica