Quando una colonna contiene valori di tipo NULL come dobbiamo interpretarne il significato? Come comportarci nel calcolo di aggregati, nell'aggiornamento e nel confronto fra dati con valori NULL? In quest'articolo cercheremo risposte concrete.
Il significato di NULL
SQL Server considera il NULL come un "non valore". Difatti non un numero e nemmeno una stringa vuota, semplicemente "non è". Vediamo come consentire o negare l'uso di NULL all'interno delle colonne durante la creazione di una tabella:
Use tempdb
GO
CREATE TABLE T_PROVA
(
[ID] INTEGER NOT NULL, //UN VINCOLO, LA COLONNA NON ACCETTA VALORI NULL!
[TESTO] VARCHAR(200)
)
INSERT INTO T_PROVA ([ID]) VALUES (1)
INSERT INTO T_PROVA ([ID],[TESTO]) VALUES (2,DEFAULT)
INSERT INTO T_PROVA ([ID],[TESTO]) VALUES (3,NULL)
SELECT * FROM T_PROVA
La tabella T_PROVA possiede due colonne: la prima denominata ID, la quale non accetta valori NULL in virtù del vincolo NOT NULL specificato in fase di creazione, e la seconda, TESTO, che non avendo specificato nessun vincolo consente l'immissione di valori NULL. L'inserimento di alcune righe di test nella tabella ci conferma che:
- possiamo negare l'uso di valori NULL nelle colonne grazie all'uso del vincolo NOT NULL in fase di creazione della tabella
- se non esistono vincoli specifici, le colonne di una tabella consentono l'immissione di valori NULL
Vediamo ora la creazione di altra tabella:
CREATE TABLE T_PROVA2
(
[ID] INTEGER PRIMARY KEY, //VINCOLO CHIAVE PRIMARIA NON ACCETTA VALORI NULL
[TESTO] VARCHAR(200) DEFAULT('PROVA')
)
INSERT INTO T_PROVA2 ([ID],[TESTO]) VALUES (NULL,'Testo')
INSERT INTO T_PROVA2 ([ID],[TESTO]) VALUES (1,NULL)
INSERT INTO T_PROVA2 ([ID],[TESTO]) VALUES (2,DEFAULT)
INSERT INTO T_PROVA2 ([ID],[TESTO]) VALUES (3,'Testo')
In questa seconda tabella la colonna ID è la chiave primaria e quindi non accetta mai valori NULL, al contrario la seconda sì, anche se abbiamo definito su di essa un DEFAULT. Per vietare l'immissione di NULLS nella colonna TESTO dovremmo modificare l'istruzione con:
[TESTO] VARCHAR(200) DEFAULT('PROVA') NOT NULL
Ancora una considerazione, supponiamo di avere una colonna PREZZO con valori NULL all'interno di una ipotetica tabella PRODOTTO, questo non significa che esistano prodotti senza un prezzo, ma solamente che il prezzo di alcuni prodotti è sconosciuto o non è stato ancora valorizzato.
Questa distinzione deve essere chiara perché influenza il disegno del database, quindi comprendere la corretta gestione dei valori NULL è fondamentale per non incorrere in errori di progettazione.
Riassumendo:
- Per testare i valori NULL nella clausola WHERE delle query dobbiamo usare le parole chiave IS [NOT] NULL.
- Se eseguiamo una query all'interno del Query Analyzer, nel pannello dei risultati i valori NULL sono indicati chiaramente nella griglia dalla parola "NULL" all'interno delle celle.
- I valori NULL possono essere inseriti e aggiornati all'interno di una colonna usando la parola chiave NULL oppure lasciando la colonna vuota durante l'uso dell'istruzione INSERT
- I valori NULL sono abilitati all'interno delle colonne durate la creazione o la modifica delle stesse, mediante l'istruzione CREATE o ALTER TABLE
- Non dobbiamo usare mai i valori NULL come informazione per distinguere una riga di una tabella da altra riga in un'altra tabella (utilizzare le chiavi primarie e esterne).
Le parole chiave IS NULL e IS NOT NULL
Entrambe servono per determinare se l'espressione specificata è NULL e restituiscono un valore booleano, vediamo alcuni esempi di utilizzo:
SELECT * FROM Books WHERE price < 10 OR price IS NULL
La query restituisce tutti i libri con un prezzo inferiore a 10 Euro oppure con prezzo sconosciuto.
UPDATE Books SET price=0 WHERE price IS NULL
La query aggiorna i libri con prezzo sconosciuto a 0.
DELETE Books WHERE price IS NULL
La query elimina tutti i libri con prezzo sconosciuto dalla tabella BOOKS.
Per determinare se un'espressione è pari a NULL, dobbiamo sempre utilizzare la funzione IS NULL o IS NOT NULL anziché i normali operatori di confronto, come = o <>, i quali restituiscono UNKNOWN se uno o entrambi gli argomenti sono NULL.
La funzione ISNULL
Sostituisce il valore NULL con il valore di sostituzione specificato, un esempio:
SELECT * FROM Books WHERE ISNULL(title,'') <> ''
La query restituisce tutti i libri che possiedono un titolo.
SELECT * FROM Books WHERE ISNULL(quantity,-1) > 50
La query restituisce tutti i libri che hanno una giacenza superiore a 50, tutti i valori NULL nella colonna quantity saranno sostituiti dal valore indicato nella funzione ISNULL, cioè -1.
SELECT AVG(ISNULL(price, 5)) FROM Books
In questo esempio viene calcolata il prezzo medio di un libro, effettuando la sostituzione dei valori NULL della colonna price con un valore pari a 5.
SELECT SUBSTRING(title, 1, 15) AS Title, ISNULL(price, 0) AS
Price
FROM Books
In questo esempio viene formattata una query per visualizzare una lista in cui i prezzi con valore NULL saranno sostituiti dallo 0 nell'output.
Comparare i valori NULL
SQL Server implementa lo standard ANSI SQL, per cui i valori NULL non sono paragonabili al contenuto di una colonna con l'operatore "=". Supponiamo di avere una stored procedure simile a questa:
CREATE PROCEDURE dbo.P_CERCA_ORDINI @DATA_SPEDIZIONE DATETIME
AS
SELECT * FROM dbo.Orders WHERE ShippedDate = @DATA_SPEDIZIONE
GO
EXEC dbo.P_CERCA_ORDINI '1996-07-23'
Questa procedura funzionerà correttamente finché immetteremo date valide per @DATA_SPEDIZIONE, diversamente se il parametro viene valorizzato a NULL l'istruzione non restituirà nessuna riga.
Questo comportamento non è corretto, difatti controllando la tabella ORDERS possiamo constatare la presenza di diverse righe con ShippedDate pari a NULL. Per ottenere il risultato corretto dobbiamo modificare la procedura in questo modo:
IF @DATA_SPEDIZIONE IS NULL
SELECT * FROM dbo.Orders WHERE ShippedDate IS NULL
ELSE
SELECT * FROM dbo.Orders WHERE ShippedDate = @DATA_SPEDIZIONE
Abbiamo aggiunto un costrutto IF ELSE per verificare che il parametro @DATA_SPEDIZIONE non sia NULL. In caso affermativo verrà eseguita la query principale, in caso contrario verrà eseguita una query alternativa in grado di restituire tutte righe della tabella ORDERS con data di spedizione pari a NULL.
Conclusione
In questo articolo abbiamo esaminato il significato e la corretta gestione dei valori NULL all'interno di SQL Server.