Wyobraź sobie, że łączysz dwie tabele: students (studenci) i enrollments (zapisy na kursy). Jeśli w tabeli enrollments nie ma info o jakimś studencie, ale używasz np. LEFT JOIN, wiersze z tabeli students i tak się pojawią, ale info z enrollments będzie brakować. Zamiast konkretnych danych w takich przypadkach pojawia się NULL.
Wygląda to mniej więcej tak:
Tabela students:
| id | name |
|---|---|
| 1 | Eva |
| 2 | Peter |
| 3 | Anna |
Tabela enrollments:
| student_id | course_name |
|---|---|
| 1 | Matematyka |
| 1 | Informatyka |
| 2 | Fizyka |
Zapytanie z LEFT JOIN:
SELECT students.id, students.name, enrollments.course_name
FROM students
LEFT JOIN enrollments ON students.id = enrollments.student_id;
Wynik:
| id | name | course_name |
|---|---|---|
| 1 | Eva | Matematyka |
| 1 | Eva | Informatyka |
| 2 | Peter | Fizyka |
| 3 | Anna | NULL |
No hej, NULL! Jak widzisz, dla Anny, która nie jest zapisana na żaden kurs, info o kursie nie istnieje i pojawia się NULL.
Jak NULL wpływa na zapytania?
NULL to nie "zero" i nie "pusty string", to brak wartości. Takie zachowanie ma kilka ciekawych (i czasem wkurzających) konsekwencji:
Porównania z NULL:
Jeśli napiszesz coś w stylu WHERE course_name = NULL, zapytanie nie zwróci wierszy z NULL. Dlaczego? Bo z NULL nie da się porównywać wartości bezpośrednio.
Żeby sprawdzić, czy jest NULL, trzeba użyć specjalnych operatorów:
WHERE course_name IS NULL
Operacje matematyczne:
Każda operacja z NULL zwraca NULL. Na przykład:
SELECT 5 + NULL; -- wynik: NULL
Funkcje agregujące:
Większość funkcji agregujących, takich jak SUM(), AVG(), ignoruje NULL, ale COUNT(*) liczy je jako "istniejące wiersze".
Jak ogarnąć NULL?
- Zamiana
NULLna czytelne wartości przezCOALESCE()
Funkcja COALESCE() pozwala zamienić NULL na inną wartość. Na przykład, jeśli kursu brak, możesz podać "Brak kursu":
SELECT
students.id,
students.name,
COALESCE(enrollments.course_name, 'Brak kursu') AS course_name
FROM
students LEFT JOIN enrollments
ON students.id = enrollments.student_id;
Wynik:
| id | name | course_name |
|---|---|---|
| 1 | Eva | Matematyka |
| 1 | Eva | Informatyka |
| 2 | Peter | Fizyka |
| 3 | Anna | Brak kursu |
Teraz wygląda to dużo lepiej, prawda?
- Filtrowanie
NULLwartości
Jeśli nie chcesz widzieć wierszy z NULL, możesz użyć warunku WHERE ... IS NOT NULL. Na przykład:
SELECT
students.id,
students.name,
enrollments.course_name
FROM
students LEFT JOIN enrollments
ON students.id = enrollments.student_id
WHERE
enrollments.course_name IS NOT NULL;
Wynik:
| id | name | course_name |
|---|---|---|
| 1 | Eva | Matematyka |
| 1 | Eva | Informatyka |
| 2 | Peter | Fizyka |
Anna znika z wyniku, bo nie ma zapisów na kursy.
- Liczenie z uwzględnieniem
NULL: przykład zCOUNT
Jak już wspomniałem, niektóre funkcje ignorują NULL, a niektóre nie. Na przykład:
Żeby policzyć wszystkie wiersze, także te, gdzie jest NULL:
SELECT COUNT(*) FROM students; -- Liczy WSZYSTKIE wiersze (także te, gdzie `course_name` = NULL)
Żeby policzyć tylko wiersze, gdzie nie ma NULL:
SELECT COUNT(course_name) FROM enrollments;
- Wyrażenia warunkowe z
CASE
Jeśli nie podoba Ci się COALESCE() albo chcesz więcej kontroli, spróbuj użyć CASE. Na przykład:
SELECT
students.id,
students.name,
CASE
WHEN enrollments.course_name IS NULL THEN 'Brak kursu'
ELSE enrollments.course_name
END AS course_name
FROM
students LEFT JOIN enrollments
ON students.id = enrollments.student_id;
Wynik będzie taki sam jak przy użyciu COALESCE(), ale CASE pozwala opisać bardziej złożone zasady.
- Używaj
INNER JOIN, jeśli masz pewność, że nie będzieNULL
Najbardziej radykalny sposób na uniknięcie NULL — po prostu nie dopuszczać do ich pojawienia się, używając INNER JOIN. Ten typ joinów zwraca tylko wiersze z dopasowaniami w obu tabelach:
SELECT
students.id,
students.name,
enrollments.course_name
FROM
students INNER JOIN enrollments
ON students.id = enrollments.student_id;
Bez niespodzianek — tylko studenci zapisani na kursy.
Wynik:
| id | name | course_name |
|---|---|---|
| 1 | Eva | Matematyka |
| 1 | Eva | Informatyka |
| 2 | Peter | Fizyka |
Jeśli Twoje dane wymagają pokazania wszystkich wartości, także NULL, INNER JOIN się nie sprawdzi, ale czasem to wszystko, czego potrzebujesz.
GO TO FULL VERSION