Первые шаги в SQL для аналитика: ошибки новичков
За 20–30 минут вы соберёте простую выборку заказов, посчитаете выручку и увидите, почему NULL, неверный GROUP BY и фильтр не по тому полю дают ошибочные результаты. Примеры рассчитаны на PostgreSQL 16.

За 20–30 минут вы создадите небольшую таблицу заказов, отфильтруете оплаченные покупки и посчитаете выручку по месяцам. По пути разберёте ошибки, из-за которых начинающий аналитик получает пустую выборку или сумму, которой в данных нет. Примеры написаны для PostgreSQL 16.
Что понадобится
Нужен доступ к PostgreSQL 16 и SQL-редактор, который выполняет запросы в базе: например, встроенный редактор в вашей аналитической платформе или клиент для PostgreSQL. Создавать постоянную таблицу и менять чужие данные не придётся: в примере используется временная таблица. Запускайте запросы в одной сессии — такая таблица доступна только в текущем соединении.
Если у вас другая СУБД, например MySQL, базовые SELECT, WHERE и GROUP BY будут знакомы, но функции для работы с датами могут отличаться. Не переносите запросы с date_trunc без проверки документации вашей версии.
Первые пять шагов
Создайте данные для упражнения
Выполните целиком: сначала создаётся временная таблица, затем в неё добавляются шесть тестовых заказов.
CREATE TEMP TABLE orders ( order_id integer PRIMARY KEY, order_date date NOT NULL, customer_id integer NOT NULL, status text NOT NULL, amount numeric(10, 2) ); INSERT INTO orders (order_id, order_date, customer_id, status, amount) VALUES (1, '2025-01-03', 101, 'paid', 1200.00), (2, '2025-01-03', 102, 'paid', 800.00), (3, '2025-01-05', 101, 'cancelled', 500.00), (4, '2025-02-01', 103, 'paid', 1500.00), (5, '2025-02-12', 101, 'paid', NULL), (6, '2025-02-12', 104, 'paid', 700.00);Проверка: запрос
SELECT * FROM orders;вернёт шесть строк. Если редактор сообщает, что таблица уже существует, выполните упражнение в новом соединении или удалите временную таблицу и запустите блок заново.Выберите нужные строки
Не начинайте с
SELECT *, если уже знаете, какие поля нужны. Явно укажите столбцы и условие. Текстовые значения в PostgreSQL заключают в одинарные кавычки.SELECT order_id, order_date, amount FROM orders WHERE status = 'paid' ORDER BY order_date;Проверка: вернутся пять оплаченных заказов. Отменённая покупка не попадёт в результат. Сортировка нужна, когда порядок строк важен: без
ORDER BYбаза не обещает конкретную последовательность.Посчитайте итог без группировки
COUNT(*)считает строки, аSUM(amount)складывает заполненные значения столбца. Отфильтруйте отменённые заказы до подсчёта.SELECT COUNT(*) AS paid_orders, SUM(amount) AS paid_revenue FROM orders WHERE status = 'paid';Проверка: результат — пять оплаченных строк и сумма 4200. Один из пяти заказов содержит пустую сумму, поэтому
SUMего не прибавит. Если посчитать только строки, где сумма известна, используйтеCOUNT(amount): здесь получится четыре, а не пять.Разбейте выручку по месяцам
Чтобы получить отдельный итог для каждого месяца, добавьте группировку по выражению месяца. В PostgreSQL 16
date_truncобрезает дату до указанной части; здесь результат преобразуется обратно в тип даты.SELECT date_trunc('month', order_date)::date AS month, SUM(amount) AS revenue FROM orders WHERE status = 'paid' GROUP BY date_trunc('month', order_date)::date ORDER BY month;Проверка: запрос вернёт две строки — за январь и февраль 2025 года. В первом месяце сумма равна 2000, во втором — 2200. Поле в
SELECT, которое не обёрнуто агрегатной функцией, должно участвовать в группировке.Найдите незаполненные суммы
Для проверки на отсутствие значения используйте
IS NULL, а не сравнение с нулём. Нулевая сумма — число, аNULLозначает, что значение неизвестно или не задано.SELECT order_id, order_date FROM orders WHERE amount IS NULL;Проверка: появится заказ с номером 5. Теперь вы отличаете отсутствие суммы от настоящего заказа на ноль рублей.
Ошибки, которые меняют результат
| Ошибка | Что происходит | Как исправить |
|---|---|---|
status = paid | PostgreSQL воспринимает paid как имя столбца и может ответить column "paid" does not exist. | Текстовое значение пишите в одинарных кавычках: status = 'paid'. |
amount = NULL | Запрос не находит строку с пустой суммой: сравнение с NULL не работает как обычное сравнение. | Используйте amount IS NULL или amount IS NOT NULL. |
| Столбец в SELECT не включён в GROUP BY | PostgreSQL выдаёт ошибку: column must appear in the GROUP BY clause or be used in an aggregate function. | Добавьте столбец или выражение в GROUP BY либо посчитайте его агрегатной функцией. |
| Условие по сумме в WHERE | Агрегат ещё не рассчитан на этапе фильтрации строк; база сообщит, что агрегатные функции нельзя использовать в WHERE. | Для фильтра по результату группировки применяется HAVING. Это следующий шаг после освоения базовой группировки. |
| COUNT(*) принимают за число заполненных сумм | В выборке считаются все строки, в том числе с пустым amount. | Выберите COUNT(amount), если нужно считать только строки с известной суммой. |
Термин: NULL. Это специальное значение, которое обозначает отсутствие данных, а не число 0 и не пустую строку. Поэтому для него используют проверки IS NULL и IS NOT NULL, а агрегаты вроде SUM не включают NULL в расчёт.
Запрос может выполниться без ошибки и всё равно ответить не на тот вопрос. Сначала определите, что именно нужно посчитать: строки, заполненные значения или сумму по отфильтрованным данным.
Что делать дальше
Перед тем как применять запрос к отчёту, проверьте три вещи: какие строки отсекает WHERE, что именно считает агрегат и по каким полям строится группировка. Затем сравните общий итог с простым подсчётом исходных строк: это помогает заметить пропущенные статусы и пустые значения.
Следующая тема — соединение таблиц по ключам. На заказах и клиентах особенно легко случайно размножить строки и завысить выручку, поэтому до JOIN научитесь проверять уникальность ключа и число строк в результате. Для рабочей базы также уточните, какие поля разрешено читать и какой период данных нужен отчёту.
IT-архитектор / SQL-оптимизатор: Поиск N+1, оптимизация запросов, code review, поиск багов.
Спросить за 20 ₽Источники: PostgreSQL 16: Tutorial, PostgreSQL 16: Aggregate Functions
Частые вопросы
Подойдут ли запросы, если у меня не PostgreSQL?
Почему сумма не совпадает с числом оплаченных заказов?
Чем NULL отличается от нуля?
Почему PostgreSQL требует добавить столбец в GROUP BY?
Что делать, если таблица orders не найдена?
Безопасно ли запускать эти запросы в рабочей базе?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.