CodeGym /Kursy /SQL SELF /Wyrażenia warunkowe: CASE WHEN ... THEN ... ELSE ... END

Wyrażenia warunkowe: CASE WHEN ... THEN ... ELSE ... END

SQL SELF
Poziom 10, Lekcja 0
Dostępny

Pewnie już spotkałeś się z wyrażeniami warunkowymi w językach programowania: if-else, switch-case i podobne konstrukcje. W SQL mamy swój własny sposób na warunki: to wyrażenie CASE. Pozwala ono podejmować decyzje bezpośrednio w zapytaniach: jeśli warunek jest spełniony, zrób jedno, jeśli nie — coś innego.

Konstrukcja CASE jest szczególnie przydatna, gdy musisz pracować z danymi, które mogą mieć wartości NULL. Składnia jest prosta jak ściąga, zobaczmy:

CASE
    WHEN warunek1 THEN wynik1
    WHEN warunek2 THEN wynik2
    ...
    ELSE wynik_domyslny
END

Brzmi logicznie, nie? "Jeśli jest tak, zrób to, w przeciwnym razie zrób coś innego". Łatwo zapamiętać: "WHEN — to jeśli, THEN — co zrobić, ELSE — co zrobić, jeśli nic nie pasuje".

Przykład: klasyfikacja produktów

Wyobraź sobie, że mamy tabelę products, w której jest kolumna price, i chcemy podzielić produkty na grupy w zależności od ich ceny.

id name price
1 Magic Wand 120
2 Potion Set 45
3 Crystal Ball 75
4 Enchanted Map NULL
5 Broomstick 99
6 Spell Book 180
SELECT
    name AS product_name,
    price,
    CASE
        WHEN price IS NULL THEN 'Nieznany'
        WHEN price < 50 THEN 'Budżetowy'
        WHEN price BETWEEN 50 AND 100 THEN 'Standardowy'
        ELSE 'Premium'
    END AS price_category
FROM products;

Co tu się dzieje?

  1. Jeśli cena price produktu nie jest podana NULL, wyświetlamy kategorię jako 'Nieznany'.
  2. Jeśli cena jest mniejsza niż 50, produkt jest budżetowy 'Budżetowy'.
  3. Jeśli cena jest w zakresie od 50 do 100, trafia do kategorii 'Standardowy'.
  4. Wszystko inne — to produkty premium 'Premium'.

Oto wynik:

product_name price price_category
Magic Wand 120 Premium
Potion Set 45 Budżetowy
Crystal Ball 75 Standardowy
Enchanted Map NULL Nieznany
Broomstick 99 Standardowy
Spell Book 180 Premium

SQL, jak czarodziej, czyta wiersze tabeli products, stosuje się do każdego i sprytnie klasyfikuje.

Praca z NULL w CASE WHEN

Często zdarza się, że w danych są brakujące wartości (siema, NULL), i trzeba je czymś zastąpić. Na przykład mamy tabelę users z kolumną email, i dla użytkowników bez maila chcemy wyświetlić 'Nie podano'.

user_id name email
1 Alex Lin alex@example.com
2 Maria Chi NULL
3 Anna Song anna@magic.com
4 Otto Art NULL
5 John Smith john@wizard.org
SELECT
    user_id,
    name,
    CASE
        WHEN email IS NULL THEN 'Nie podano'
        ELSE email
    END AS email_address
FROM users;
user_id name email_address
1 Alex Lin alex@example.com
2 Maria Chi Nie podano
3 Anna Song anna@magic.com
4 Otto Art Nie podano
5 John Smith john@wizard.org

SQL tutaj działa jak szaman, ożywiając półpuste wiersze. Jeśli email nie istnieje, zamienia go na tekst 'Nie podano'. Jeśli email jest — po prostu go zostawia.

Wyrażenia warunkowe z liczbami

Czasem trzeba nie tylko podmienić wartości, ale też zbudować nową logikę. Na przykład, mamy tabelę students z kolumnami score (ocena) i name.

name score
Alex Lin 95
Maria Chi 82
Anna Song 48
Otto Art NULL
John Smith 67
Zoe Black 30

Chcemy ocenić studentów jako "Świetny", "Zaliczony" i "Niezaliczony", w zależności od ich punktów.

SELECT
    name AS student_name,
    score,
    CASE
        WHEN score IS NULL THEN 'Brak Wyniku'
        WHEN score >= 90 THEN 'Świetny'
        WHEN score >= 50 THEN 'Zaliczony'
        ELSE 'Niezaliczony'
    END AS performance_category
FROM students;
student_name score performance_category
Alex Lin 95 Świetny
Maria Chi 82 Zaliczony
Anna Song 48 Niezaliczony
Otto Art NULL Brak Wyniku
John Smith 67 Zaliczony
Zoe Black 30 Niezaliczony

SQL grzecznie rozdziela studentów, jak surowy egzaminator: 90 punktów i więcej — tylko "Świetny", od 50 — "Zaliczony". A jak punktów brakuje... no, wiadomo.

Grupowanie i obsługa NULL

Praca z grupami danych — to kolejny obszar, gdzie CASE WHEN błyszczy. Wyobraź sobie, że mamy tabelę orders, i chcemy policzyć łączną liczbę zamówień według statusu, wliczając zamówienia ze statusem NULL.

order_id status
1 Completed
2 Pending
3 NULL
4 Shipped
5 Completed
6 NULL
7 Pending
8 Completed
9 Shipped
10 NULL
SELECT
    CASE
        WHEN status IS NULL THEN 'Brak Statusu'
        ELSE status
    END AS order_status,
    COUNT(*)
FROM orders
GROUP BY 
    CASE
        WHEN status IS NULL THEN 'Brak Statusu'
        ELSE status
    END;

To zapytanie elegancko obsługuje puste statusy NULL i wstawia 'Brak Statusu' zamiast nich, a także liczy łączną liczbę zamówień w każdej grupie. Oto wynik:

order_status count
Completed 3
Pending 2
Shipped 2
Brak Statusu 3

Praktyczne przypadki: "Sztuczki" z CASE WHEN

Przykład 1: Sortowanie z uwzględnieniem NULL

Czasem wartości NULL trzeba wyświetlić albo na początku, albo na końcu posortowanej listy. To często się przydaje np. w listach zadań, gdzie priorytetowe zadania mają być wyżej, a zadania bez priorytetu (NULL) na końcu.

task_id task_name priority
1 Fix bugs 1
2 Update documentation 3
3 Plan sprint NULL
4 Code review 2
5 Organize meeting NULL
6 Deploy release 1
SELECT
    task_name,
    priority,
    CASE
        WHEN priority IS NULL THEN 1
        ELSE 0
    END AS priority_sort
FROM tasks
ORDER BY priority_sort ASC, priority ASC;

Dodaliśmy tu "wirtualną" kolumnę priority_sort, która ustawia NULL na końcu, a resztę sortuje rosnąco.

task_name priority priority_sort
Deploy release 1 0
Fix bugs 1 0
Code review 2 0
Update documentation 3 0
Plan sprint NULL 1
Organize meeting NULL 1

Przykład 2: Obliczenia z uwzględnieniem NULL

Wyobraź sobie, że liczymy końcową sumę zamówienia w tabeli orders, gdzie w kolumnie discount zniżka może być NULL, jeśli jej nie ma.

order_id total_price discount
101 100 10
102 200 NULL
103 150 15
104 120 NULL
105 80 5

Musimy zamienić NULL na 0, żeby obliczenia się nie wywaliły.

SELECT 
    order_id,
    total_price,
    discount,
    total_price - 
    CASE
        WHEN discount IS NULL THEN 0
        ELSE discount
    END AS final_price
FROM orders;
order_id total_price discount final_price
101 100 10 90
102 200 NULL 200
103 150 15 135
104 120 NULL 120
105 80 5 75

Ten magiczny trik z CASE pozwala mieć pewność, że NULL nie rozwali nam obliczeń.

Dla orderid = 101: discount = 10. finalprice = 100 - 10 = 90. Dla orderid = 102: discount = NULL. CASE zwraca 0. finalprice = 200 - 0 = 200. Dla orderid = 103: discount = 15. finalprice = 150 - 15 = 135. Dla orderid = 104: discount = NULL. CASE zwraca 0. finalprice = 120 - 0 = 120. Dla orderid = 105: discount = 5. finalprice = 80 - 5 = 75.

Przykład 3: Wyświetlanie statusów użytkowników

W codziennej pracy często trzeba pokazać status użytkownika (np. "Aktywny" albo "Oczekuje") lub wskazać brak danych. Na przykład w tabeli users jest kolumna last_login, gdzie trzymana jest data ostatniego logowania.

user_id name last_login
1 Alex Lin 2024-12-10
2 Maria Chi 2025-04-20
3 Anna Song NULL
4 Otto Art 2025-05-01
5 Liam Park 2025-05-25
SELECT
    user_id,
    name,
    CASE
        WHEN last_login IS NULL THEN 'Nigdy nie logował się'
        WHEN last_login < CURRENT_DATE - INTERVAL '30 days' THEN 'Nieaktywny'
        ELSE 'Aktywny'
    END AS user_status
FROM users;

Z tym zapytaniem system admina ożywa: użytkowników bez logowania nazywa "Nigdy nie logował się", a tych, którzy dawno nie byli, uznaje za "Nieaktywny". Reszta jest aktywna!

user_id name user_status
1 Alex Lin Nieaktywny
2 Maria Chi Nieaktywny
3 Anna Song Nigdy nie logował się
4 Otto Art Nieaktywny
5 Liam Park Aktywny

Typowe błędy i jak ich unikać

Brak ELSE: Jeśli nie dodasz ELSE, SQL po prostu zwróci NULL, jeśli żaden warunek nie będzie spełniony. To nie zawsze to, czego chcesz. Dlatego lepiej zawsze jawnie podać ELSE, nawet jeśli jesteś pewien, że ogarnąłeś wszystkie przypadki.

CASE
    WHEN condition THEN result
    -- ELSE 'Wartość domyślna' -- nie zapomnij!
END

Złożone warunki bez nawiasów: Jeśli masz kilka złożonych warunków z AND, OR albo NOT, zawsze używaj nawiasów. Bez nich twój query może zacząć "myśleć" źle.

CASE
    WHEN (column1 IS NOT NULL AND column2 > 5) THEN 'Poprawny'
    ELSE 'Niepoprawny'
END

Praca z NULL: Pamiętaj, że NULL nigdy nie jest równy (=) czemukolwiek. Na przykład:

CASE
    WHEN column = NULL THEN 'Nope!' -- Błąd!
    WHEN column IS NULL THEN 'Poprawnie!' -- O to chodzi.
END
2
Zadanie
SQL SELF, poziom 10, lekcja 0
Niedostępne
Warunkowe wyświetlanie brakujących danych
Warunkowe wyświetlanie brakujących danych
2
Zadanie
SQL SELF, poziom 10, lekcja 0
Niedostępne
Przypisywanie kategorii na podstawie wartości liczbowych
Przypisywanie kategorii na podstawie wartości liczbowych
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION