7 SQL-запросов, которые решают 90% всех задач на работе

Каждый день одно и то же. Открываешь клиент базы данных, чтобы что-то проверить, посчитать или найти. И снова пишешь почти тот же SELECT, что и вчера, с тем же WHERE и JOIN. Знакомо?

SQL в большинстве случаях не требует сложные 100-строчные запросы с вложенными подзапросами на три уровня глубины. Чаще всего нам нужны простые, отточенные и, главное, эффективные конструкции.

В этой статье я собрал 7 таких запросов-«рабочих лошадок». Это не какой-то там справочник, а готовая шпаргалка для реальных задач.

Прежде чем перейти к запросам, запомните главное правило любого UPDATE или DELETE: всегда сначала пишите SELECT с теми же условиями WHERE.

Серьёзно, всегда. Это убережёт вас от случайного изменения или удаления не тех данных. Один мой знакомый в начале карьеры однажды чуть не отправил в архив несколько гигабайт production-данных из-за неверного условия. С тех пор он, да и я тоже делаем так:

-- Шаг 1: Сначала СМОТРИМ, что будем обновлять/удалять
SELECT * FROM orders WHERE status = 'test';

-- Шаг 2: Убедившись, что выборка корректна, заменяем на UPDATE/DELETE
DELETE FROM orders WHERE status = 'test';

Теперь, когда этот критически важный ритуал усвоен, перейдём к тем самым «рабочим лошадкам».

❯ 1. Ежедневный мониторинг

Как обычно, первым делом с утра нам нужно проверить, что система жива, данные поступают, ничего не сломалось ночью. Без ORDER BY и LIMIT можно случайно выгрузить всю таблицу и подвесить клиент, чего явно нам не хотелось бы.

SELECT id, status, created_at, amount
FROM latest_transactions
WHERE status = 'processed'
ORDER BY created_at DESC
LIMIT 10;

Ключевая привычка — всегда использовать ORDER BY для детерминированности и LIMIT для безопасности.

Допустим, вы увидели, что данные поступают. Что дальше? Обычно следом просят свестить итоги и подготовить отчет.

❯ 2. Агрегация данных

Самый частый запрос для любого отчёта. Посчитать количество, сумму, среднее значение по группам. Здесь на первый план выходят GROUP BY и агрегатные функции.

SELECT
    user_id,
    COUNT(*) AS total_orders,
    SUM(amount) AS total_revenue
FROM orders
WHERE created_at >= '2024-01-01'
GROUP BY user_id
HAVING SUM(amount) > 1000
ORDER BY total_revenue DESC;

Считает выручку по каждому пользователю с начала года, но показывает только «VIP-клиентов», принесших больше 1000 единиц. Запомните: WHERE фильтрует строки догруппировки, а HAVING — после.

Готовя отчеты, но вы вдруг замечаете аномалии: некоторые цифры не сходятся. Есть подозрение на дубликаты.

❯ 3. Охота за дубликатами

Дубликаты — вечная головная боль. Они появляются из-за ошибок в логике приложения, сбоев и багов. Их нужно уметь быстро находить. Спасет GROUP BY и HAVING.

SELECT
    email,
    COUNT(*) AS duplicate_count
FROM users
GROUP BY email
HAVING COUNT(*) > 1;

Находит все email-адреса, которые встречаются в таблице пользователей больше одного раза. Это отправная точка для «зачистки».

Дубликаты найдены. Чтобы принять осмысленное решение по ним, нужно больше информации. Пора заглянуть в связанные таблицы.

❯ 4. Объединение данных из нескольких таблиц

Данные в нормализованной базе всегда разбросаны. Чтобы получить полную картину, нужны JOIN-ы.

SELECT
    u.first_name,
    u.last_name,
    o.order_date,
    o.total_amount,
    p.product_name
FROM users u
INNER JOIN orders o ON u.id = o.user_id
LEFT JOIN products p ON o.product_id = p.id
WHERE u.country = 'Germany'
ORDER BY o.order_date DESC;

Главное — не запутаться в их типах.

Их всего 3:
INNER JOIN — только совпадающие записи с обеих сторон

LEFT JOIN — все записи из левой таблицы + совпадения справа

RIGHT JOIN — все записи из правой таблицы + совпадения слева

Объединив данные, вы обнаруживаете сложную закономерность: нужно найти записи, которые соответствуют условию на основе других данных.

❯ 5. Запросы в запросах

Когда простых условий WHERE уже недостаточно, на помощь приходят подзапросы. Они позволяют вложить один запрос в другой для сложной фильтрации.

SELECT *
FROM products
WHERE price > (
    SELECT AVG(price)
    FROM products
    WHERE category_id = 5
)
AND category_id = 5;

Находит все товары в категории 5, цена которых выше средней по этой же категории. Идеально для поиска аномалий и выбросов.

Проанализировав данные, вы понимаете, что пора не просто смотреть, а что-то менять. Самое опасное — модификация данных.

❯ 6. Модификация данных с умом

Вот мы и дошли до самого опасного — UPDATE и DELETE. Здесь правило только одно: семь раз отмерь, один раз выполни. Всегда начинай с SELECT.

-- ШАГ 1: Сначала смотрим, что будем менять
SELECT *
FROM users
WHERE last_login < '2024-01-01'
AND active = true;

-- ШАГ 2: Только затем выполняем UPDATE (и лучше в транзакции!)
BEGIN;

UPDATE users
SET active = false
WHERE last_login < '2024-01-01'
AND active = true;

-- Смотрим, что получилось, и только потом COMMIT или ROLLBACK
COMMIT;

Данные обновлены. Теперь нужно проанализировать результат в разрезе времени или групп, не схлопывая строки. Обычного GROUP BY уже мало.

❯ 7. Оконные функции

Финальный аккорд — мощные оконные функции (OVERPARTITION BY). Они позволяют делать агрегацию без группировки, сохраняя все исходные строки.

SELECT
    product_id,
    sale_date,
    daily_revenue,
    SUM(daily_revenue) OVER (
        PARTITION BY product_id
        ORDER BY sale_date
    ) AS cumulative_revenue
FROM sales
ORDER BY product_id, sale_date;

Для каждого товара рассчитывает нарастающий итог выручки по дням. В отличие от GROUP BY, мы видим каждую продажу, а не только итог.

Вот и все. Этих 7 запросов хватит, чтобы уверенно чувствовать себя в 90% рабочих ситуаций с SQL. Они покрывают весь цикл работы с данными: от ежедневного мониторинга до сложной аналитики и аккуратной модификации.

 

Источник: https://habr.com/ru/companies/timeweb/articles/943298/