NULL

W terminologii SQL wartość NULL jest określeniem dla brakującej wartości potocznie zwanej pustym polem.

Całkowitym przeciwieństwem jest wyrażnie NOT NULL, które pozwoli nam zrozumieć cały mechanizm.

Posługując się wiedzą zdobytą w poprzednich wpisach przygotujemy nową tabelę wraz z kilkoma kolumnami. Pierwsza z nich będzie kluczem główny, kolejne będą reprezentowały różne typy danych. Na dwie z nich nałożymy ograniczenie NOT NULL określające, że akceptowane są tylko jawane wartości danego typu. Dwie kolumny będą pozbawione tego ograniczenia – prześledzimy zachowanie tabeli z wykorzystaniem polecenia INSERT.

W pierwszej kolejności utworzymy nową tabelę:

CREATE TABLE Cars (
	Id INT IDENTITY(1,1) PRIMARY KEY, -- klucz główny z indeksowaniem od 1 co 1
	Brand VARCHAR(20) NOT NULL,       -- marka samochodu jako pole wymagane
	Model VARCHAR(20) NOT NULL,       -- model samochodu jako pole wymagane
	Engine VARCHAR(20),               -- oznaczenie silnika jako pole niewymagane   
	Power INT,                        -- moc samochodu również nie jest wymagana
)

Pierwszy INSERT będzie dodawał do tabeli wszystkie dane:

-- Polecenie dodaje jeden rekord do tabeli Cars
INSERT INTO Cars(Brand,Model, Engine, Power) VALUES ('Audi', 'S8 D3', 'V10 5.2', 450);
Dodajmy drugi rekord z wartością pustą dla mocy danego silnika:
-- Polecenie dodaje jeden rekord do tabeli Cars
INSERT INTO Cars(Brand,Model, Engine, Power) VALUES ('Audi', 'RS6 C5', 'V8 4.2', NULL);
Oraz trzeci z wartością pustą dla silnika oraz jego mocy:
-- Polecenie dodaje jeden rekord do tabeli Cars
INSERT INTO Cars(Brand,Model, Engine, Power) VALUES ('Audi', 'RS6 C6', NULL, NULL);
Zanim przejdziemy dalej zobaczymy jakie dane zostały zapisane: SQL - NULL

Kolumny tabeli (Engine, Power) akceptują wartości NULL a my w sposób świadomy tych danych nie przekazaliśmy. Pola te nie są równoznacze wstawieniu samych znaków spacji – pamiętajcie o tym.

Spróbujmy jeszcze 'złamać' nasze ograniczenia zdefiowane dla tej tabeli poniższym zapytaniem:

-- Wykonanie polecenia rzuca wyjątek
-- Cannot insert the value NULL into column 'Brand', table 'AdventureWorks2017.dbo.Cars'; 
-- column does not allow nulls. INSERT fails.
INSERT INTO Cars(Brand, Model, Engine, Power) VALUES (NULL, NULL, NULL, NULL);

Problem

Wartość NULL może być nieco problematyczna podczas pobierania danych z bazy danych. Porównanie wartości pustej do jakiejkolwiek innej wartości zawsze daje wynik nieznany – taki rekord nie jest uwzględniany w zwracanych wynikach. Znacie jakiś obecnie produkowany samochód, którego moc jest mniejsza niż 78 koni mechanicznych? Zobaczmy co na ten temat powie nasze zapytanie:

-- takie zapytanie nie zwraca żadnych wyników
SELECT * FROM Cars
WHERE Power < 78

Nie wspomniałem tego wcześniej – teraz możecie się tego domyślać. Wartość NULL nijak ma się również do przysłowiowego zera. Porównanie jawnej wartości (78) do wartości NULL dało wynik nieznany a takie rekordy nie zostały zwrócone w wynikach wyszukiwania. Dodatkowo nie został zwrócony rekord z Audi S8 ponieważ jego moc kilkukrotnie przewyższa 78 zdefiniowane w warunku WHERE.

Co zatem możemy zrobić? Możemy wykorzystać operator IS NULL lub IS NOT NULL celem zwrócenia interesujących nas rekordów.

Jeżeli chcemy zwrócić wszystkie rekordy dla których w kolumnie Power zdefiniowano moc silnika posłużymy się poniższą składnią:

-- zapytanie zwraca jeden rekord
SELECT * FROM Cars 
WHERE Power IS NOT NULL

Jeżeli jednak chcemy dokonać aktualizacji brakujących danych możemy wykonać poniższe polecenie, które zwróci nam rekordy z brakującymi danymi dotyczącymi mocy silnika:

-- zapytanie zwraca dwa rekordy
SELECT * FROM Cars
WHERE Power IS NULL