Как написать SQL-запрос: пошаговый пример

Что такое SQL-запрос

SQL-запрос — команда, которую вы отправляете базе данных, чтобы получить нужные данные.

Пример: «Покажи всех пользователей из Москвы».

SELECT * FROM users WHERE city = 'Moscow';

Это читается как обычный текст: «выбери всё из таблицы users, где city = 'Moscow'».

Структура запроса

Любой SQL-запрос имеет до 6 основных частей:

SELECT    -- что выбрать
FROM      -- откуда
WHERE     -- с каким фильтром
GROUP BY  -- сгруппировать по
HAVING    -- фильтр на группы
ORDER BY  -- как сортировать
LIMIT     -- сколько строк

Не все части обязательны. Минимум — SELECT ... FROM ....

Пошаговый пример

Задача: «Найти топ-5 городов по выручке от заказов в апреле 2026, только города с 10+ заказами».

Шаг 1. SELECT и FROM

Начинаем с нужных полей и таблицы:

SELECT city FROM orders;

Возвращает города всех заказов (с повторами).

Шаг 2. Добавляем JOIN

Выручка — в orders, города — в users. Нужно соединить:

SELECT u.city, o.amount
FROM orders o
JOIN users u ON u.user_id = o.user_id;

Теперь видим пары (город, сумма).

Шаг 3. Фильтр по дате

Только апрель 2026:

SELECT u.city, o.amount
FROM orders o
JOIN users u ON u.user_id = o.user_id
WHERE o.created_at >= '2026-04-01' AND o.created_at < '2026-05-01';

Шаг 4. GROUP BY

Суммируем по городам:

SELECT u.city, SUM(o.amount) AS total
FROM orders o
JOIN users u ON u.user_id = o.user_id
WHERE o.created_at >= '2026-04-01' AND o.created_at < '2026-05-01'
GROUP BY u.city;

Шаг 5. HAVING

Оставляем города с 10+ заказами:

SELECT u.city, SUM(o.amount) AS total, COUNT(*) AS orders_cnt
FROM orders o
JOIN users u ON u.user_id = o.user_id
WHERE o.created_at >= '2026-04-01' AND o.created_at < '2026-05-01'
GROUP BY u.city
HAVING COUNT(*) >= 10;

Шаг 6. ORDER BY + LIMIT

Сортируем по выручке, берём топ-5:

SELECT u.city, SUM(o.amount) AS total, COUNT(*) AS orders_cnt
FROM orders o
JOIN users u ON u.user_id = o.user_id
WHERE o.created_at >= '2026-04-01' AND o.created_at < '2026-05-01'
GROUP BY u.city
HAVING COUNT(*) >= 10
ORDER BY total DESC
LIMIT 5;

Готово.

Больше таких примеров с разборами — в Telegram-тренажёре. Короткие сессии, прогресс по темам, объяснения после каждого ответа.

Порядок выполнения (важно!)

Хотя пишем SELECT ... FROM ... WHERE ..., СУБД выполняет в другом порядке:

  1. FROM + JOIN
  2. WHERE
  3. GROUP BY
  4. HAVING
  5. SELECT
  6. ORDER BY
  7. LIMIT

Отсюда:

  • В WHERE нельзя использовать агрегаты (GROUP BY ещё не сделан).
  • Алиасы из SELECT не всегда работают в WHERE (SELECT выполняется позже).

Советы для новичков

1. Пишите запрос постепенно

Начните с SELECT * FROM table LIMIT 10 — посмотрите, что в таблице. Добавляйте усложнения.

2. Всегда используйте alias для таблиц

FROM orders o JOIN users u ON ...

Короче и читабельнее.

3. Форматируйте код

SELECT
    u.city,
    SUM(o.amount) AS total
FROM orders o
JOIN users u ON u.user_id = o.user_id
WHERE ...

Не пишите всё одной строкой.

4. Комментируйте сложные части

-- Считаем только paid-заказы за апрель
WHERE o.status = 'paid'
  AND o.created_at >= '2026-04-01'
  AND o.created_at < '2026-05-01'

5. Тестируйте на маленьких данных

Добавьте LIMIT 100 пока пишете — быстрее итерируете.

Типичные ошибки новичка

1. Забыть GROUP BY

-- ❌ Ошибка: city не агрегат и не в GROUP BY
SELECT city, SUM(amount) FROM orders;

-- ✅
SELECT city, SUM(amount) FROM orders GROUP BY city;

2. Integer division

-- ❌ Возвращает 0, а не 0.5
SELECT 1 / 2;

-- ✅
SELECT 1.0 / 2;

3. Путать WHERE и HAVING

  • WHERE — фильтр строк (до группировки).
  • HAVING — фильтр групп (после).

4. LEFT JOIN превращается в INNER

-- ❌ Потеряем пользователей без заказов
SELECT u.name, o.amount
FROM users u
LEFT JOIN orders o ON ...
WHERE o.status = 'paid';

-- ✅ Условие в ON, не в WHERE
SELECT u.name, o.amount
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id AND o.status = 'paid';

Если готовишься к собесу — бот @kariernik_bot закрывает 80% технических вопросов. SQL, Python, A/B, продуктовые метрики — всё в одном месте.

Что учить дальше

  1. Оконные функции — для ранжирования, MoM, нарастающих итогов. Шпаргалка.
  2. CTE (WITH) — для читаемых сложных запросов. Шпаргалка.
  3. Подзапросы — для условий через SELECT. Шпаргалка.
  4. Работа с датами — DATE_TRUNC, EXTRACT. Шпаргалка.

Читайте также

FAQ

Где написать свой первый запрос?

Установите PostgreSQL + DBeaver (бесплатно). Или используйте онлайн-песочницу: SQL Fiddle, тренажёр Карьерник.

Как учить SQL?

  1. Базовый курс (Stepik, SQL Academy).
  2. 5 задач в день.
  3. Через 4 недели — JOIN, GROUP BY в голове.
  4. Через 2 месяца — оконные и CTE.

Какой SQL учить — MySQL или PostgreSQL?

Начинайте с PostgreSQL — стандартнее и функциональнее. Перейти на MySQL потом — легко, отличий мало.

Чем отличается SQL на собесе от реального?

На собесе много про «тонкости» (CASE WHEN, оконные, LEFT vs INNER). На работе — больше про понимание бизнеса и чистоту кода.