W tym wykładzie jeszcze lepiej poznamy tajemniczego znajomego NULL. Oczywiście, twoje własne błędy z nim dopiero przed tobą, ale... kto ostrzeżony, ten uzbrojony. Przejdziemy przez kilka typowych błędów związanych z NULL.
Błąd 1: Używanie zwykłego operatora = do sprawdzania NULL
Chyba najpopularniejszy błąd wśród początkujących w SQL — próba użycia operatora = do sprawdzenia, czy wartość to NULL.
Co się dzieje?
SELECT *
FROM students
WHERE age = NULL;
Myśląc naiwnie, że to pokaże wszystkich studentów z nieokreślonym wiekiem, będziesz rozczarowany: to zapytanie nie zwróci nic. Dlaczego? Chodzi o to, że NULL nie jest wartością, więc zwykłe operatory porównania z nim nie działają. Jak mówi magiczna księga SQL: "NULL nie można porównywać bezpośrednio z niczym".
Jak powinno być?
Żeby sprawdzić, czy wartość to NULL, użyj IS NULL:
SELECT *
FROM students
WHERE age IS NULL;
Teraz dostaniesz wszystkich studentów, których wiek nie jest podany.
Błąd 2: Funkcje agregujące ignorują NULL (oprócz COUNT(*))
Kiedy wykonujesz zapytania z funkcjami agregującymi, NULL jest automatycznie pomijany w obliczeniach. To może prowadzić do nieoczekiwanych wyników.
Co się dzieje?
SELECT AVG(salary) AS avg_salary
FROM employees;
Jeśli w kolumnie salary jest NULL, takie wiersze są po prostu ignorowane i średnia pensja będzie liczona bez nich. To może dać fałszywe wyobrażenie o średnim wynagrodzeniu.
Jak tego uniknąć?
Zanim użyjesz agregacji, upewnij się, że poprawnie zamieniasz NULL na wartość domyślną. Na przykład, użyj COALESCE():
SELECT AVG(COALESCE(salary, 0)) AS avg_salary
FROM employees;
Teraz NULL zostanie zamienione na 0 przed obliczeniem.
Błąd 3: Porównywanie NULL między sobą
W bazie danych NULL nie jest równy dosłownie niczemu, nawet innemu NULL. To może być zaskoczenie.
Co się dzieje?
SELECT *
FROM students
WHERE NULL = NULL;
To zapytanie też zwróci pusty wynik. Dlaczego? Bo SQL uważa, że brak jednej wartości nie może być "równy" brakowi innej. Tak, SQL to filozoficzny język.
Jak powinno być?
Jeśli chcesz sprawdzić dwa NULL pod kątem "równości", użyj specjalnych konstrukcji jak IS NULL. Na przykład:
SELECT *
FROM students
WHERE first_name IS NULL AND last_name IS NULL;
Błąd 4: Dzielenie przez NULL
Dzielenie przez NULL — to nie tylko błąd, ale wręcz matematyczne przestępstwo, które SQL karze bezsensownym wynikiem — NULL.
Co się dzieje?
SELECT 10 / NULL AS result;
Wynik? NULL. SQL nawet nie próbuje zrozumieć, o co ci chodzi.
Jak tego uniknąć?
Żeby zabezpieczyć swoje zapytania przed takimi wpadkami, użyj COALESCE() albo NULLIF():
SELECT 10 / COALESCE(divisor, 1) AS result
FROM calculations;
W tym zapytaniu, jeśli divisor okaże się NULL, zamiast dzielenia przez NULL będzie dzielenie przez 1.
Błąd 5: Niesprawne operatory logiczne z NULL
NULL rozwala logikę, jak tylko pojawi się w wyrażeniach. Na przykład, warunek TRUE AND NULL zwróci NULL, a nie TRUE ani FALSE.
Co się dzieje?
SELECT *
FROM students
WHERE age > 18 OR age = NULL;
W tym przypadku nawet jeśli age > 18 jest prawdziwe dla niektórych rekordów, część wierszy z NULL w kolumnie age może być pominięta w wyniku. Dlaczego? Bo część wyrażenia age = NULL zwróci NULL, a nie TRUE.
Jak powinno być?
Zawsze jawnie obsługuj NULL w warunkach logicznych:
SELECT *
FROM students
WHERE age > 18 OR age IS NULL;
Błąd 6: Nieoczywiste zachowanie przy sortowaniu NULL (najbardziej "ciężki" błąd)
Jeśli w zapytaniu używasz ORDER BY, zachowanie NULL może cię zaskoczyć. Domyślnie PostgreSQL sortuje wiersze z NULL na końcu przy sortowaniu rosnącym i na początku przy sortowaniu malejącym.
Co się dzieje?
SELECT product_name, price
FROM products
ORDER BY price;
Jeśli price ma NULL, te wiersze pojawią się na końcu listy.
Jak uniknąć niespodzianek?
Możesz jawnie ustawić sortowanie dla NULL używając NULLS FIRST albo NULLS LAST:
SELECT product_name, price
FROM products
ORDER BY price NULLS FIRST;
Błąd 7: Zła praca z kluczami obcymi i NULL
NULL w kolumnach z kluczami obcymi może czasem prowadzić do nieoczekiwanego zachowania.
Co się dzieje?
Jeśli dodałeś klucze obce do tabeli i próbujesz wstawić wiersz zostawiając pole klucza obcego puste, PostgreSQL nie da żadnego znaku życia. To dlatego, że NULL nie jest sprawdzany pod kątem zgodności z powiązanymi tabelami.
Jak pracować poprawnie?
Użyj ograniczenia NOT NULL, jeśli chcesz wykluczyć możliwość użycia NULL w takich polach. Albo po prostu pamiętaj, że NULL zostaje "sierotą", nie należącą do żadnej powiązanej tabeli.
Więcej o powiązanych tabelach i kluczach obcych dowiesz się w następnym wykładzie :P
GO TO FULL VERSION