Скоріш за все, ти вже стикався з умовними виразами в мовах програмування: if-else, switch-case та подібними конструкціями. В SQL є свій інструмент для роботи з умовами: це вираз CASE. Він дозволяє приймати рішення прямо в запитах: якщо умова виконується — зробити одне, якщо ні — інше.
Конструкція CASE особливо корисна, коли треба працювати з даними, які можуть містити NULL значення. Синтаксис простий, як шпаргалка, дивись:
CASE
WHEN умова1 THEN результат1
WHEN умова2 THEN результат2
...
ELSE результат_за_замовчуванням
END
Логічно, правда? "Якщо так — зроби це, інакше — інше". Запам’ятати легко: "WHEN — це якщо, THEN — що робити, ELSE — що робити, якщо нічого не підійшло".
Приклад: класифікація товарів
Уяви, що у нас є таблиця products, де є колонка price, і ми хочемо розподілити товари по групах залежно від їхньої ціни.
| 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 'Невідомо'
WHEN price < 50 THEN 'Бюджетний'
WHEN price BETWEEN 50 AND 100 THEN 'Стандартний'
ELSE 'Преміум'
END AS price_category
FROM products;
Що тут відбувається?
- Якщо ціна
priceу товару не вказанаNULL, ми показуємо категорію як'Невідомо'. - Якщо ціна менше 50, товар вважається бюджетним
'Бюджетний'. - Якщо ціна в діапазоні від 50 до 100, він потрапляє в категорію
'Стандартний'. - Все інше — це товари преміум-класу
'Преміум'.
Ось результат:
| product_name | price | price_category |
|---|---|---|
| Magic Wand | 120 | Преміум |
| Potion Set | 45 | Бюджетний |
| Crystal Ball | 75 | Стандартний |
| Enchanted Map | NULL | Невідомо |
| Broomstick | 99 | Стандартний |
| Spell Book | 180 | Преміум |
SQL, як справжній чарівник, читає рядки таблиці products, застосовує до кожної і хитро класифікує.
Робота з NULL у CASE WHEN
Часто буває, що в даних є пропущені значення (привіт, NULL), і їх треба чимось замінити. Наприклад, у нас є таблиця users з колонкою email, і для користувачів без електронної пошти ми хочемо показати 'Не вказано'.
| user_id | name | |
|---|---|---|
| 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 'Не вказано'
ELSE email
END AS email_address
FROM users;
| user_id | name | email_address |
|---|---|---|
| 1 | Alex Lin | alex@example.com |
| 2 | Maria Chi | Не вказано |
| 3 | Anna Song | anna@magic.com |
| 4 | Otto Art | Не вказано |
| 5 | John Smith | john@wizard.org |
SQL тут працює як шаман, оживляючи напівпорожні рядки. Якщо email відсутній, він підставляє текст 'Не вказано'. Якщо email є — просто залишає його.
Умовні вирази з числами
Іноді треба не просто замінити значення, а й побудувати нову логіку. Наприклад, у нас є таблиця students зі стовпцями score (оцінка) і name.
| name | score |
|---|---|
| Alex Lin | 95 |
| Maria Chi | 82 |
| Anna Song | 48 |
| Otto Art | NULL |
| John Smith | 67 |
| Zoe Black | 30 |
Ми хочемо оцінювати студентів як "Успішний", "Нормальний" і "Неуспішний", залежно від їхніх балів.
SELECT
name AS student_name,
score,
CASE
WHEN score IS NULL THEN 'Немає оцінки'
WHEN score >= 90 THEN 'Відмінно'
WHEN score >= 50 THEN 'Зараховано'
ELSE 'Не зараховано'
END AS performance_category
FROM students;
| student_name | score | performance_category |
|---|---|---|
| Alex Lin | 95 | Відмінно |
| Maria Chi | 82 | Зараховано |
| Anna Song | 48 | Не зараховано |
| Otto Art | NULL | Немає оцінки |
| John Smith | 67 | Зараховано |
| Zoe Black | 30 | Не зараховано |
SQL люб’язно розподіляє студентів, як суворий екзаменатор: 90 балів і вище — тільки "Відмінно", від 50 — "Зараховано". А якщо балів не вистачає... ну, ти зрозумів.
Групування і обробка NULL
Робота з групами даних — ще одна сфера, де CASE WHEN блискуче себе показує. Уяви, що у нас є таблиця orders, і ми хочемо порахувати загальну кількість замовлень по статусу, включаючи замовлення зі статусом 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 'Без статусу'
ELSE status
END AS order_status,
COUNT(*)
FROM orders
GROUP BY
CASE
WHEN status IS NULL THEN 'Без статусу'
ELSE status
END;
Цей запит акуратно обробляє порожні статуси NULL і підставляє 'Без статусу' замість них, а також рахує загальну кількість замовлень у кожній групі. Ось результат:
| order_status | count |
|---|---|
| Completed | 3 |
| Pending | 2 |
| Shipped | 2 |
| Без статусу | 3 |
Практичні кейси: "Фокуси" з CASE WHEN
Приклад 1: Сортування з урахуванням NULL
Іноді NULL значення треба показувати або першими, або останніми у відсортованому списку. Це часто використовується, наприклад, у списках задач, де пріоритетні задачі мають бути вище, а задачі без пріоритету (NULL) — в кінці.
| 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;
Тут ми додали "віртуальну" колонку priority_sort, яка ставить NULL значення нижче всіх, а інші сортує за зростанням.
| 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 |
Приклад 2: Обчислення з урахуванням NULL
А тепер уяви, що ми рахуємо підсумкову суму замовлення в таблиці orders, де в колонці discount знижка може бути NULL, якщо її немає.
| order_id | total_price | discount |
|---|---|---|
| 101 | 100 | 10 |
| 102 | 200 | NULL |
| 103 | 150 | 15 |
| 104 | 120 | NULL |
| 105 | 80 | 5 |
Треба замінити NULL на 0, щоб розрахунок не ламався.
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 |
Цей магічний трюк з CASE дозволяє бути впевненим, що NULL не зламає математику.
Для orderid = 101: discount = 10. finalprice = 100 - 10 = 90. Для orderid = 102: discount = NULL. CASE повертає 0. finalprice = 200 - 0 = 200. Для orderid = 103: discount = 15. finalprice = 150 - 15 = 135. Для orderid = 104: discount = NULL. CASE повертає 0. finalprice = 120 - 0 = 120. Для orderid = 105: discount = 5. finalprice = 80 - 5 = 75.
Приклад 3: Відображення статусів користувачів
У повсякденній роботі часто треба показати статус користувача (наприклад, "Активний" чи "В очікуванні") або вказати на відсутність даних. Наприклад, у таблиці users є колонка last_login, де зберігається дата останнього входу.
| 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 'Жодного входу'
WHEN last_login < CURRENT_DATE - INTERVAL '30 days' THEN 'Неактивний'
ELSE 'Активний'
END AS user_status
FROM users;
З цим запитом система адміна оживає: користувачів без входу називають "Жодного входу", а тих, хто давно не заходив — "Неактивний". Інші — активні!
| user_id | name | user_status |
|---|---|---|
| 1 | Alex Lin | Неактивний |
| 2 | Maria Chi | Неактивний |
| 3 | Anna Song | Жодного входу |
| 4 | Otto Art | Неактивний |
| 5 | Liam Park | Активний |
Поширені помилки і як їх уникнути
Пропуск ELSE: Якщо ти не додаси ELSE, SQL просто поверне NULL, якщо жодна умова не виконається. Це не завжди те, що ти хочеш. Тому краще явно вказувати ELSE, навіть якщо впевнений, що врахував усе.
CASE
WHEN condition THEN result
-- ELSE 'Значення за замовчуванням' -- не забудь!
END
Складні умови без дужок: Якщо у тебе кілька складних умов з AND, OR чи NOT, завжди використовуй дужки. Без них твій запит може "думати" неправильно.
CASE
WHEN (column1 IS NOT NULL AND column2 > 5) THEN 'Валідно'
ELSE 'Не валідно'
END
Робота з NULL: Пам’ятай, що NULL ніколи не дорівнює (=) чомусь. Наприклад:
CASE
WHEN column = NULL THEN 'Ні!' -- Помилка!
WHEN column IS NULL THEN 'Правильно!' -- Ось це правильно.
END
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ