Documenti FirebirdGuida sull'uso di NULL nel linguaggio SQL di Firebird → NULL nelle espressioni
Firebird home Firebird home Indietro: Cosa è NULL?Partenza: Documenti FirebirdRisali: Guida sull'uso di NULL nel linguaggio SQL di FirebirdAvanti: Gestione dei NULL nelle UDF

NULL nelle espressioni

Espressioni che riportano NULL
NULL nelle espressioni logiche
Ancora logica (anche se non sembra)
NULL nelle funzioni di aggregazione

Come molti di noi hanno scoperto con sconforto, NULL è contagioso: usato in una espressione numerica, di stringhe, o data/ora, il risultato sarà sempre e comunque NULL. Usandolo invece in una operazione logica, il risultato dipende dal tipo dell'operazione e degli altri valori coinvolti.

Notare, inoltre, che nelle versioni di Firebird precedenti alla 2.0 è abbastanza illegale utilizzare NULL direttamente nelle operazioni o nei confronti. Dovunque si vede NULL nelle seguenti espressioni, va letto come “un campo, una variabile o altra espressione che vale NULL”.

Espressioni che riportano NULL

Le espressioni nella seguente lista riportano sempre e comunque tutte NULL:

  • 1 + 2 + 3 + NULL

  • 'Casa ' || 'dolce ' || NULL

  • IlMioCampo = NULL

  • IlMioCampo <> NULL

  • NULL = NULL

  • not (NULL)

Se si ha proprio difficoltà a capire perchè, basta rammentare che NULL significa “sconosciuto”. Guardiamo ora nella seguente tabella, dove sono spiegate caso per caso tutte le precedenti espressioni. In questa tabella non usiamo NULL nelle espressioni (come già accennato, questo è spesso illegale); invece usiamo due entità, diciamo A e B, che sono entrambe NULL. A e B possono essere campi, variabili, od intere sottoespressioni, le quali, fintantochè sono di valore NULL, si comportano sempre allo stesso modo nelle espressioni mostrate.

Tabella 1. Operazioni sulle entità null A and B

Se A e B sono NULL, allora: vale per questo motivo
1 + 2 + 3 + A NULL Se A è sconosciuto, allora anche 6 + A è sconosciuto.
'Casa ' || 'dolce ' || A NULL Se A è sconosciuto, 'Casa dolce ' || A è sconosciuto.
IlMioCampo = A NULL Se A è sconosciuto, non si può dire se IlMioCampo ha lo stesso valore...
IlMioCampo <> A NULL ...ma non si può neanche dire se IlMioCampo ha un valore differente!
A = B NULL Se A e B sono sconosciuti, è impossibile sapere se sono uguali.
not (A) NULL Se A è sconosciuto, è sconosciuto anche il suo inverso (o la sua negazione).

NULL nelle espressioni logiche

Abiamo già visto che not(NULL) vale NULL. Con gli operatori and e or, le cose sono un po' più complicate:

  • NULL or false = NULL

  • NULL or true = true

  • NULL or NULL = NULL

  • NULL and false = false

  • NULL and true = NULL

  • NULL and NULL = NULL

Firebird SQL non ha un tipo di dato boolean; nè true o false sono costanti definite. Nella colonna a sinistra della tabella successiva, (true) e (false) rappresentano delle sottoespressioni che valgono true oppure false (ad esempio: 1=1 è sempre vero, 1=0 è sempre falso).

Tabella 2. Operazioni logiche sull'entità di valore null A

Se A è NULL, allora vale per questo motivo
A or (false) NULL A or false” ha sempre il valore di A - che è sconosciuto.
A or (true) true A or true” è sempre true, perchè il valore di A non ha importanza.
A or A NULL A or A” è sempre A, che è sconosciuto, cioè NULL.
A and (false) false A and false” è sempre falso, perchè il valore di A non conta.
A and (true) NULL A and true” ha sempre il valore di A - che è sconosciuto.
A and A NULL A and A” è sempre A, che è sconosciuto, cioè NULL.

Tutti questi risultati sono in accordo con la logica booleana. Il fatto che non si ha la necessità di conoscere il valore di X per calcolare “X or true” e “X and false” è alla base di una caratteristica nota in molti linguaggi di programmazione col nome di short-circuit boolean evaluation (valutazione logica cortocircuitata).

Ancora logica (anche se non sembra)

I risultati determinati dai cortocircuiti logici booleani di cui sopra possono suggerire le seguenti idee:

  • 0 per x è uguale a 0 per qualsiasi x. Pertanto, anche se x è sconosciuto, 0 * x vale 0. (N.B.: questo solo se il tipo di dato di x può contenere solo numeri, non NaN o infiniti.)

  • La stringa vuota è in ordine lessicografico prima di ogni altra stringa. Pertanto, S >= '' è vero per qualsiasi valore di S.

  • Ogni valore è uguale a sé stesso, sia conosciuto che incognito. Così, sebbene sia giustificato che A = B sia NULL quando A e B sono entità diverse di valore NULL, invece A = A dovrebbe sempre riportare true, anche quando A è NULL.

Ebbene, come viene implementato questo in Firebird SQL? È mio dovere informare che, contrariamente al buon senso e all'analogia con i risultati dell'algebra booleana mostrati sopra, tutte le seguenti espressioni valgono NULL:

  • 0 * NULL

  • NULL >= ''

  • '' <= NULL

  • A = A (dove A è una variabile o un campo null)

Il fatto è che non vanno confusi gli operatori logici (quali OR e AND) con gli operatori quali la moltiplicazione ed il confronto che sono operatori aritmetici che hanno risultati rispettivamente numerici o booleani.

NULL nelle funzioni di aggregazione

Nelle funzioni di aggregazione, come COUNT, SUM, AVG, MAX, e MIN, un campo a NULL è gestito in modo differente: per calcolare il risultato, solo i campi che non sono NULL (in breve “campi non-NULL”) vengono presi in considerazione. Pertanto, con questi dati:

TabellaMia

ID Nome Importo
1 John 37
2 Jack <NULL>
3 Joe 5
4 Josh 12
5 Jay <NULL>

...eseguendo select sum(Importo) from TabellaMia riporta 54, che è appunto 37 + 5 + 12. Se fossero stati sommati tutti i cinque campi, il risultato sarebbe stato NULL. Per la funzione AVG, i campi non-NULL sono sommati tra loro, e la somma divisa per il numero dei campi non-NULL.

C'è una eccezione a questa regola: COUNT(*) riporta il numero di tutte le righe, perfino di quelle in cui tutti i campi sono NULL. Ma COUNT(NomeCampo) si comporta come le altre funzioni aggregate, nel senso che conta solo le righe in cui quello specifico campo non è NULL.

Un'altra cosa che vale la pena di sapere è che sia COUNT(*) sia COUNT(FieldName) non riportano mai NULL: se non ci sono righe nell'insieme risultato della SELECT..., entrambe valgono 0. Inoltre, anche COUNT(NomeCampo) vale 0 se tutti i campi NomeCampo nel risultato sono NULL. In questi casi tutte le altre funzioni di aggregazione riportano NULL. Bisogna avvertire che anche SUM riporta NULL se utilizzata su un insieme risultato vuoto, che è contrario alla logica comune.

Riassumendo, con i dati della TabellaMia di esempio riportati all'inizio, si ha

Tabella 3. Operazioni di aggregazione su valori null
select ... risultato
select sum(Importo) from MiaTabella 54
select avg(importo) from MiaTabella 18
select count(*) from MiaTabella 5
select count(Importo) from MiaTabella 3
select count(*) from MiaTabella where ID > 5 0
select count(Importo)from MiaTabella where Nome >= 'M' 0
select count(Importo) from MiaTabella where ID in (2,5) 0
select sum(Importo) from MiaTabella where ID > 5 <NULL>
Indietro: Cosa è NULL?Partenza: Documenti FirebirdRisali: Guida sull'uso di NULL nel linguaggio SQL di FirebirdAvanti: Gestione dei NULL nelle UDF
Documenti FirebirdGuida sull'uso di NULL nel linguaggio SQL di Firebird → NULL nelle espressioni