SQLучебникдля начинающихNULLCASECASTCOALESCEчасть-7

SQL с нуля. Часть 7: NULL, типы данных, COALESCE, CAST, CASE WHEN

2026-06-02 8 мин

Это часть 7 из 10 учебника «SQL с нуля для аналитика». Содержание серии в конце поста. ← Часть 6


TL;DR: NULL означает «нет данных», не равен ничему (даже NULL). Сравнивать через IS NULL / IS NOT NULL. COALESCE(x, default) подменяет NULL на значение. CAST(x AS type) меняет тип. CASE WHEN cond THEN val ... END — условная логика. Эти 4 темы решают 80% data quality проблем.

В этой части:


Что такое NULL и почему он опасен?

NULL — не «ноль» и не «пустая строка». Это «нет значения».

!NULL — три правила распространения: арифметика, сравнение, агрегаты

Как NULL «портит» всю формулу — и как COALESCE спасает:

!NULL cascade: ошибка распространяется через колонки

3 главных правила:

-- В таблице 10 строк, у 3 amount IS NULL, у 7 значения 100, 200, ..., 700

SELECT SUM(amount) FROM orders;       -- 2800 (7 строк × среднее)
SELECT AVG(amount) FROM orders;       -- 400 (среднее по 7, не по 10)
SELECT COUNT(*) FROM orders;          -- 10 (все строки)
SELECT COUNT(amount) FROM orders;     -- 7 (только не-NULL)
Типичный случай: разработчик добавил колонку без default — все старые строки получили NULL. Аналитик считает SUM(amount - discount), получает SUM = NULL для старых заказов. Фикс: SUM(amount - COALESCE(discount, 0)).

Как фильтровать NULL?

Только через IS NULL / IS NOT NULL:

-- Удалённые юзеры
SELECT * FROM users WHERE deleted_at IS NOT NULL;

-- Активные юзеры
SELECT * FROM users WHERE deleted_at IS NULL;
WHERE col = NULL или WHERE col != NULLникогда не делай.

Какие 6 типов данных нужно знать?

ТипЧто хранитПример
INTEGER / BIGINTЦелое числоid, count
NUMERIC(p,s) / DECIMALТочное дробноеmoney, percentage
FLOAT / DOUBLEПриближённое дробноеsensor data
TEXT / VARCHARСтрокаname, email
DATE / TIMESTAMPДата / дата-времяcreated_at
BOOLEANtrue / falseis_active

Правило для денег: всегда NUMERIC(18,2) или DECIMAL, не FLOAT. FLOAT теряет копейки из-за binary precision.

-- FLOAT теряет: 0.1 + 0.2 ≠ 0.3 (даёт 0.30000000000000004)
-- NUMERIC точно: 0.10 + 0.20 = 0.30

Как заменить NULL на значение по умолчанию?

COALESCE(val1, val2, ..., default) — возвращает первое не-NULL.
-- Если nickname NULL — показать email
SELECT COALESCE(nickname, email, 'anonymous') AS display_name
FROM users;

-- Если discount NULL — считать 0
SELECT amount - COALESCE(discount, 0) AS final_amount
FROM orders;

Альтернатива COALESCENULLIF(a, b) (возвращает NULL если a=b). Реже нужно.

Типичный случай: дашборд CEO «средняя выручка на пользователя» показывает NULL первое число месяца — потому что среди новых пользователей нет ещё заказов. Фикс: COALESCE(AVG(revenue), 0).

Как преобразовать тип через CAST?

CAST(value AS type) или короткая форма value::type (PG-специфика):
-- Строка в число
SELECT CAST('123' AS INTEGER);
SELECT '123'::INTEGER;  -- PG syntax

-- Число в строку
SELECT CAST(123 AS TEXT);
SELECT 123::TEXT;

-- Точное дробное
SELECT CAST(amount AS NUMERIC(18,2));
SELECT amount::NUMERIC(18,2);

-- Дата
SELECT CAST('2026-06-02' AS DATE);
SELECT '2026-06-02'::DATE;

Подвох: если 'abc' нельзя сконвертировать в INTEGER — runtime error. Используй TRY_CAST (MS SQL) или SAFE_CAST (BigQuery) для безопасной конверсии.

Что такое CASE WHEN и когда его использовать?

CASE WHEN cond1 THEN val1 WHEN cond2 THEN val2 ELSE valN END — условная логика, как if/elif/else.
-- Категоризация юзеров по выручке
SELECT
    user_id,
    SUM(amount) AS total,
    CASE
        WHEN SUM(amount) >= 100000 THEN 'VIP'
        WHEN SUM(amount) >= 10000 THEN 'Loyal'
        WHEN SUM(amount) >= 1000 THEN 'Regular'
        ELSE 'New'
    END AS segment
FROM orders
GROUP BY user_id;

Какие 5 частых паттернов CASE WHEN?

Конверсия в boolean

CASE WHEN status = 'paid' THEN 1 ELSE 0 END AS is_paid

Можно потом SUM(is_paid) чтобы посчитать количество оплат.

Pivot (горизонтальный разворот)

SELECT
    DATE(created_at) AS day,
    SUM(CASE WHEN country = 'RU' THEN amount END) AS revenue_ru,
    SUM(CASE WHEN country = 'KZ' THEN amount END) AS revenue_kz
FROM orders
GROUP BY day;

Категоризация (как в примере выше)

Замена пропусков (альтернатива COALESCE)

CASE WHEN col IS NULL THEN 'unknown' ELSE col END
-- эквивалентно COALESCE(col, 'unknown')

Конверсия для расчёта метрик

-- Конверсия в проценты
SUM(CASE WHEN paid THEN 1 ELSE 0 END) * 100.0 / COUNT(*) AS conversion_pct
Типичная метрика через CASE: «конверсия в оплату по каналам». SUM(CASE WHEN paid THEN 1 ELSE 0 END) * 100.0 / COUNT(*) AS conversion_pct GROUP BY channel.

Какие 5 ошибок с NULL и типами?

Частые вопросы про NULL и типы

NULL — это false?

В булевом контексте NULL ведёт себя как unknown, не false. WHERE NULL — пропускает строку.

Как INTEGER отличается от BIGINT?

INTEGER — 32 бита (до 2.1 миллиарда). BIGINT — 64 бита (до 9.2 × 10^18). Для id юзеров на большом сервисе — BIGINT.

NUMERIC или DECIMAL — что брать?

Эквивалентны. NUMERIC — стандарт ANSI, DECIMAL — синоним.

Можно ли default value на колонке вместо COALESCE?

Да, на уровне CREATE TABLE: amount NUMERIC DEFAULT 0. Но это для INSERT. SELECT уже отдаст значение или NULL.

CASE WHEN внутри агрегата — нормально?

Да, очень частый паттерн (см. конверсия). SUM(CASE WHEN paid THEN 1 ELSE 0 END) или короче COUNT(*) FILTER (WHERE paid) (PG-specific).

Что дальше?

В Части 8 — работа с датой и временем. DATE_TRUNC для группировки по месяцам, EXTRACT для извлечения года/месяца, INTERVAL для расчётов.

В Pro — безлимит мок-собесов на AI-интервью + 491 SQL-задача + 612 тестовых заданий + 50+ блог-постов.


Навигация по учебнику

← Часть 6 | Часть 7: NULL, типы, CASE | Часть 8 →

Содержание серии: 1 · 2 · 3 · 4 · 5 · 6 · 7 · 8 · 9 · 10

← Вернуться к оглавлению

Источники

SQL-тренажёр
Тренируйся работать с NULL и CASE. 491 SQL-задача, первые 5 бесплатно.
Открыть тренажёр →