SQL: полный путеводитель — от первых запросов до оконных функций

От первого SELECT до оконных функций, транзакций ACID и защиты от инъекций — всё, что нужно знать об SQL, в одном навигационном гайде с примерами кода.

Обложка: SQL: полный путеводитель — от первых запросов до оконных функций

SQL (Structured Query Language) — язык запросов для работы с реляционными базами данных, который появился больше 50 лет назад и остаётся одним из самых востребованных навыков в IT. По данным Stack Overflow Developer Survey 2024, SQL стабильно входит в тройку самых используемых языков — его применяют бэкендеры, аналитики данных, дата-инженеры и тестировщики.

Этот путеводитель — не просто список ссылок. Каждая секция содержит самостоятельный разбор темы: от истории SQL и принципов работы реляционных баз до транзакций, нормализации и защиты от инъекций. Там, где тема заслуживает глубокого погружения, мы даём ссылку на отдельную статью. Цель — дать полную карту знаний, по которой можно выстроить обучение от нуля до уверенного уровня.

Ключевые выводы

— SQL — фундаментальный навык для любого, кто работает с данными: от джуна до архитектора

— Основные команды (SELECT, JOIN, GROUP BY) покрывают 80% повседневных задач

— Порядок выполнения запроса (FROM → WHERE → GROUP BY → SELECT) — ключ к пониманию SQL

— Транзакции, ACID и уровни изоляции гарантируют надёжность данных

— Оконные функции, CTE и хранимые процедуры — продвинутый уровень для карьерного роста

— PostgreSQL — СУБД №1 в 2024 по Stack Overflow Survey, обогнавшая MySQL

— SQL не устареет: стандарт развивается, появляются JSON-запросы и графовый SQL

Что такое SQL и зачем его учить

SQL (Structured Query Language) — декларативный язык для работы с реляционными базами данных. «Декларативный» означает, что вы описываете что хотите получить, а не как это сделать. Вы пишете «дай мне все заказы за март», а СУБД сама решает, в каком порядке обходить таблицы и какие индексы использовать.

Краткая история: в 1970 году Эдгар Кодд из IBM опубликовал реляционную модель данных. В 1974 Дональд Чемберлин и Рэймонд Бойс создали язык SEQUEL (Structured English Query Language) для работы с этой моделью. Позже его переименовали в SQL из-за торговой марки. В 1986 году ANSI принял SQL как стандарт, а последняя версия — SQL:2023 — добавила поддержку JSON и графовых запросов.

Его используют бэкендеры, аналитики, дата-инженеры и даже тестировщики. И в обозримом будущем SQL никуда не денется — язык продолжает развиваться вместе со стандартом.

Как работает SQL: от запроса до результата

Когда вы отправляете SQL-запрос, внутри СУБД происходит цепочка шагов:

  1. Парсинг — СУБД разбирает текст запроса, проверяет синтаксис и строит дерево разбора
  2. Анализ — проверяет, существуют ли таблицы и столбцы, есть ли у пользователя права доступа
  3. Оптимизация — самый важный этап. Оптимизатор строит несколько вариантов плана выполнения и выбирает самый дешёвый по стоимости (I/O, CPU, память)
  4. Выполнение — движок исполняет выбранный план: сканирует таблицы, применяет фильтры, объединяет результаты
  5. Возврат результата — СУБД формирует набор строк и отправляет клиенту

Логический порядок выполнения запроса

SQL-запрос пишется в одном порядке, а выполняется в другом. Вот реальная последовательность обработки:

  1. FROM / JOIN — определяется источник данных, выполняются соединения
  2. WHERE — фильтрация строк (до группировки)
  3. GROUP BY — группировка
  4. HAVING — фильтрация групп (после группировки)
  5. WINDOW — вычисление оконных функций
  6. SELECT — выбор столбцов, вычисление выражений и алиасов
  7. DISTINCT — удаление дублей
  8. ORDER BY — сортировка (по стандарту SQL единственное место, где гарантированно работает алиас из SELECT (в PostgreSQL и MySQL алиасы также работают в GROUP BY))
  9. LIMIT / OFFSET — ограничение количества строк

Из-за этого порядка нельзя использовать алиас из SELECT в WHERE — на момент фильтрации SELECT ещё не выполнен. А HAVING работает после GROUP BY, поэтому в нём доступны агрегатные функции.

Именно благодаря оптимизатору SQL остаётся эффективным: вы пишете простой запрос, а СУБД сама выбирает, использовать ли индекс, в каком порядке объединять таблицы, нужна ли сортировка. Увидеть план выполнения можно командой EXPLAIN ANALYZE — это один из главных инструментов оптимизации.

Основные команды SQL

Любое знакомство с SQL начинается с четвёрки CRUD: SELECT (чтение), INSERT (создание), UPDATE (изменение), DELETE (удаление). К ним добавляются DDL-команды для управления структурой: CREATE TABLE, ALTER TABLE, DROP TABLE, TRUNCATE TABLE (быстрое удаление всех строк без логирования каждой).

Реальная мощь SQL раскрывается в объединениях через JOIN (INNER, LEFT, RIGHT, FULL), группировке с GROUP BY и фильтрации агрегатов через HAVING. Пример: найти средний чек по городам, где было больше 100 заказов: А также CROSS JOIN (декартово произведение всех строк) и SELF JOIN (соединение таблицы с собой — например, для поиска сотрудников и их руководителей).

			SELECT city, AVG(total) AS avg_check, COUNT(*) AS orders
FROM orders
JOIN customers ON orders.customer_id = customers.id
GROUP BY city
HAVING COUNT(*) > 100
ORDER BY avg_check DESC;
		

На практике эти команды покрывают примерно 80% задач. Полный разбор с примерами — в нашем гайде по основным командам SQL. Статью прочитали полтора миллиона раз.

Типы данных и ограничения SQL

Правильный выбор типов данных — основа производительной и надёжной базы. Базовые типы SQL:

  • Числовые: INTEGER, BIGINT, DECIMAL(10,2), FLOAT
  • Строковые: VARCHAR(255), TEXT, CHAR(10)
  • Дата и время: DATE, TIMESTAMP, INTERVAL
  • Логический: BOOLEAN
  • JSON: JSON / JSONB (PostgreSQL) — для полуструктурированных данных

Ограничения (constraints) — это правила, которые СУБД проверяет автоматически при каждой вставке и обновлении:

			CREATE TABLE users (
    id          SERIAL PRIMARY KEY,           -- уникальный идентификатор
    email       VARCHAR(255) UNIQUE NOT NULL,  -- уникальный, обязательный
    name        VARCHAR(100) NOT NULL,
    age         INT CHECK (age >= 18),         -- проверка значения
    role        VARCHAR(20) DEFAULT 'user',    -- значение по умолчанию
    team_id     INT REFERENCES teams(id)       -- внешний ключ
);
		

PRIMARY KEY гарантирует уникальность строки. FOREIGN KEY связывает таблицы и не даёт создать «висячие» ссылки. NOT NULL запрещает пустые значения. CHECK валидирует данные по условию. Вместе эти ограничения защищают целостность данных на уровне структуры — СУБД не позволит вставить строку, нарушающую правила.

Операторы и выражения

За базовыми командами идут операторы, которые делают запросы по-настоящему гибкими. WHERE фильтрует строки, LIKE ищет по шаблону с подстановочными знаками (% — любая подстрока, _ — один символ), IN проверяет вхождение в список, BETWEEN задаёт диапазон.

Отдельного внимания заслуживает CASE WHEN — условная логика прямо внутри запроса:

			SELECT name, salary,
    CASE
        WHEN salary > 200000 THEN 'senior'
        WHEN salary > 100000 THEN 'middle'
        ELSE 'junior'
    END AS level
FROM employees;
		

Подробный разбор LIKE с примерами — в отдельной статье.

NULL: подводные камни

NULL — не значение, а отсутствие значения. NULL = NULL возвращает не TRUE, а NULL. Единственный способ проверки — IS NULL / IS NOT NULL.

			-- Типичная ловушка
SELECT * FROM users WHERE name = NULL;    -- всегда 0 строк!
SELECT * FROM users WHERE name IS NULL;   -- правильно

-- COALESCE — значение по умолчанию вместо NULL
SELECT name, COALESCE(phone, email, 'нет контакта') AS contact
FROM users;

-- NULLIF — NULL если аргументы равны (защита от деления на 0)
SELECT revenue / NULLIF(expenses, 0) AS ratio FROM reports;
		

Функции даты и времени

Работа с датами — повседневная задача аналитика:

  • NOW() / CURRENT_DATE — текущий момент / дата
  • DATE_TRUNC('month', ts) — округление до начала периода
  • EXTRACT(YEAR FROM ts) — извлечение части даты
  • ts + INTERVAL '7 days' — арифметика с датами
			-- Новые пользователи по месяцам за последний год
SELECT
    DATE_TRUNC('month', created_at) AS month,
    COUNT(*) AS new_users
FROM users
WHERE created_at >= NOW() - INTERVAL '1 year'
GROUP BY 1
ORDER BY 1;
		

Строковые и математические функции

Помимо дат и агрегатов, SQL предоставляет богатый набор функций для работы со строками и числами. Строковые функции: CONCAT — склейка строк, SUBSTRING — извлечение подстроки, LENGTH — длина строки, UPPER / LOWER — смена регистра, REPLACE — замена подстроки, TRIM — удаление пробелов по краям. Математические: ROUND — округление, ABS — модуль числа, CEIL / FLOOR — округление вверх и вниз. Эти функции работают одинаково в PostgreSQL, MySQL и других СУБД (с минимальными различиями в именах).

			-- Строковые функции
SELECT
    CONCAT(first_name, ' ', last_name) AS full_name,
    UPPER(email) AS email_upper,
    LENGTH(phone) AS phone_length,
    REPLACE(address, 'ул.', 'улица') AS full_address,
    TRIM(city) AS city_clean
FROM customers;

-- Математические функции
SELECT
    product,
    price,
    ROUND(price * 0.87, 2) AS price_without_vat,
    CEIL(weight) AS weight_rounded_up
FROM products;
		

Операторы множеств: UNION, INTERSECT, EXCEPT

Эти операторы объединяют результаты нескольких запросов:

  • UNION — объединение с удалением дубликатов. UNION ALL — без удаления (быстрее)
  • INTERSECT — пересечение (строки из обоих запросов)
  • EXCEPT — разность (строки из первого, которых нет во втором)
			-- Клиенты, которые покупали в январе, но не в феврале
SELECT customer_id FROM orders WHERE month = 'jan'
EXCEPT
SELECT customer_id FROM orders WHERE month = 'feb';
		

Агрегатные функции SQL

Агрегатные функции вычисляют одно значение по набору строк: COUNT, SUM, AVG, MIN, MAX. Работают в связке с GROUP BY.

Нюансы, которые часто путают:

  • COUNT(*) считает все строки (включая NULL). COUNT(column) — только строки, где column не NULL
  • COUNT(DISTINCT column) — количество уникальных значений
  • AVG игнорирует NULL — если NULL означает «0», результат будет завышен
			-- Аналитический отчёт по отделам
SELECT
    department,
    COUNT(*) AS total,
    COUNT(DISTINCT role) AS unique_roles,
    ROUND(AVG(salary)) AS avg_salary,
    MAX(salary) - MIN(salary) AS salary_spread
FROM employees
GROUP BY department
ORDER BY avg_salary DESC;
		

Подзапросы, CTE и представления

Когда запрос становится сложным, его нужно декомпозировать. Для этого есть три инструмента.

Подзапросы

Запрос внутри запроса. Бывают скалярные (возвращают одно значение), табличные (набор строк) и коррелированные (ссылаются на внешний запрос):

			-- Найти сотрудников с зарплатой выше средней
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
		

CTE (Common Table Expressions)

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

			-- Топ-3 клиента по сумме заказов в каждом городе
WITH ranked AS (
    SELECT customer_id, city, SUM(total) AS total_spent,
           ROW_NUMBER() OVER (PARTITION BY city ORDER BY SUM(total) DESC) AS rn
    FROM orders
    JOIN customers ON orders.customer_id = customers.id
    GROUP BY customer_id, city
)
SELECT * FROM ranked WHERE rn <= 3;
		

Рекурсивные CTE

Рекурсивные CTE обходят деревья и графы — например, оргструктуру компании или вложенные категории:

			-- Дерево подчинённости: от директора до каждого сотрудника
WITH RECURSIVE org AS (
    SELECT id, name, manager_id, 1 AS depth
    FROM employees
    WHERE manager_id IS NULL  -- корень: директор
    UNION ALL
    SELECT e.id, e.name, e.manager_id, o.depth + 1
    FROM employees e
    JOIN org o ON e.manager_id = o.id
)
SELECT * FROM org ORDER BY depth, name;
		

Представления (Views)

CREATE VIEW создаёт «виртуальную таблицу» — именованный запрос, к которому можно обращаться как к обычной таблице. Это удобно для инкапсуляции сложной логики и разграничения доступа. Материализованные представления (MATERIALIZED VIEW в PostgreSQL) хранят результат физически и обновляются по команде — полезно для тяжёлых аналитических запросов.

Хранимые процедуры и функции

Хранимые процедуры и функции — SQL-код, сохранённый на сервере СУБД. Функция возвращает значение и вызывается в SELECT, процедура выполняет действия и вызывается через CALL.

Когда использовать:

  • Инкапсуляция бизнес-логики на уровне базы (расчёт скидок, начисление бонусов)
  • Повторяющиеся многошаговые операции (ежемесячные отчёты, архивация)
  • Безопасность: SECURITY DEFINER позволяет давать доступ к функции, не давая доступ к таблицам

Когда не использовать:

  • Логику приложения лучше держать в коде — её проще тестировать и деплоить
  • Тяжёлые вычисления: масштабировать сервер СУБД дороже, чем сервер приложения
  • Бизнес-логика, которая часто меняется — миграции хранимых процедур болезненнее, чем код
			-- Функция: расчёт скидки по уровню клиента
CREATE FUNCTION calc_discount(total DECIMAL, tier VARCHAR)
RETURNS DECIMAL AS $$
BEGIN
    RETURN CASE tier
        WHEN 'gold' THEN total * 0.15
        WHEN 'silver' THEN total * 0.10
        ELSE total * 0.05
    END;
END;
$$ LANGUAGE plpgsql;

-- Использование
SELECT order_id, total, calc_discount(total, tier) AS discount
FROM orders;
		

Триггеры — особый тип: они срабатывают автоматически при INSERT/UPDATE/DELETE. Полезны для аудита (логировать все изменения) и автоматических вычислений, но злоупотреблять не стоит — скрытая логика усложняет отладку.

Оконные функции SQL

Оконные функции — это то, что отделяет новичка от уверенного SQL-разработчика. Они выполняют вычисления по «окну» строк, не сворачивая результат как GROUP BY. Вы получаете и агрегат, и исходные строки одновременно.

Ключевые функции: ROW_NUMBER() для нумерации, RANK() / DENSE_RANK() для ранжирования, LAG() / LEAD() для сравнения с соседними строками, агрегатные функции с OVER() для скользящих средних и нарастающих итогов.

Типичные задачи: топ-N в каждой группе, рост метрики месяц к месяцу, скользящее среднее за 7 дней. Без оконных функций эти задачи требуют громоздких подзапросов.

			-- Рост выручки месяц к месяцу
SELECT
    month,
    revenue,
    LAG(revenue) OVER (ORDER BY month) AS prev_month,
    ROUND(
        (revenue - LAG(revenue) OVER (ORDER BY month)) * 100.0
        / LAG(revenue) OVER (ORDER BY month), 1
    ) AS growth_pct
FROM monthly_stats;
		

RANK() пропускает позиции после одинаковых значений (1, 2, 2, 4), а DENSE_RANK() — нет (1, 2, 2, 3). Для скользящих агрегатов используется конструкция ROWS BETWEEN — например, ROWS BETWEEN 6 PRECEDING AND CURRENT ROW для скользящего среднего за 7 дней.

			-- RANK vs DENSE_RANK: разница в нумерации при одинаковых значениях
SELECT
    name,
    department,
    salary,
    RANK() OVER (ORDER BY salary DESC) AS rank_pos,
    DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_pos
FROM employees;
-- salary: 120000, 100000, 100000, 90000
-- RANK:        1,       2,       2,      4
-- DENSE_RANK:  1,       2,       2,      3
		

Детальный разбор с визуальными примерами — в нашей статье об оконных функциях SQL.

Транзакции и ACID в SQL

Транзакция — группа операций, которые выполняются как единое целое: либо всё, либо ни одна. Классический пример — перевод денег:

			BEGIN;
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE id = 2;
COMMIT;  -- обе операции фиксируются атомарно
		

Если между двумя UPDATE произойдёт сбой, ROLLBACK откатит обе операции — деньги не потеряются и не удвоятся. Для частичного отката используется SAVEPOINT: можно откатить транзакцию не целиком, а до определённой точки (ROLLBACK TO SAVEPOINT имя).

Свойства ACID гарантируют надёжность транзакций:

  • Atomicity (атомарность) — транзакция неделима: либо выполнена полностью, либо отменена целиком
  • Consistency (согласованность) — после транзакции база остаётся в корректном состоянии, все ограничения соблюдены
  • Isolation (изоляция) — параллельные транзакции не мешают друг другу. Уровни: от READ UNCOMMITTED (быстро, но грязные чтения) до SERIALIZABLE (безопасно, но медленно)
  • Durability (долговечность) — после COMMIT данные сохранены даже при аварии сервера

ACID — фундамент надёжности реляционных баз данных. Именно эти свойства гарантируют, что данные не потеряются и не «рассинхронятся» даже при сбоях и параллельных запросах.

Уровни изоляции

Свойство Isolation на практике настраивается через уровни изоляции. Каждый уровень — компромисс между корректностью и производительностью:

  • READ UNCOMMITTED — самый слабый: видны незакоммиченные изменения других транзакций (dirty reads). Практически не используется
  • READ COMMITTED — видны только закоммиченные данные. По умолчанию в PostgreSQL. Достаточно для большинства приложений
  • REPEATABLE READ — повторное чтение строки всегда даёт тот же результат. По умолчанию в MySQL. Защищает от non-repeatable reads
  • SERIALIZABLE — максимальная изоляция, транзакции ведут себя как последовательные. Нужен для финансовых операций и бронирований
			-- Установить уровень для текущей транзакции
BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- ... критичные операции ...
COMMIT;
		

Нормализация и проектирование схем

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

Три ключевые нормальные формы:

  1. 1NF — каждая ячейка содержит одно атомарное значение. Никаких «Москва, Питер» в одном поле — разносим по строкам или связанным таблицам
  2. 2NF — все неключевые столбцы зависят от всего первичного ключа, а не от его части. Актуально для составных ключей
  3. 3NF — неключевые столбцы не зависят друг от друга. Если город определяет страну, нужна отдельная таблица городов

Пример: таблица заказов до и после нормализации до 3NF:

			-- ДО нормализации (всё в одной таблице):
-- | order_id | customer | city    | product | price |
-- | 1        | Иванов   | Москва  | Ноутбук | 80000 |
-- | 2        | Иванов   | Москва  | Мышь    | 1500  |
-- Проблема: город дублируется → при переезде надо менять N строк

-- ПОСЛЕ нормализации (3NF):
CREATE TABLE customers (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    city VARCHAR(100)
);

CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    customer_id INT REFERENCES customers(id),
    product VARCHAR(100),
    price DECIMAL(10,2)
);
-- Город хранится один раз → обновляется в одном месте
		

В этом примере мы устранили дублирование данных клиента (2NF). Для полной 3NF нужно было бы вынести и города в отдельную таблицу, если город определяет дополнительные атрибуты (страну, регион).

На практике большинство баз проектируют в 3NF. Но иногда данные намеренно денормализуют — например, в аналитических хранилищах (OLAP), где скорость чтения важнее экономии места. Схемы «звезда» и «снежинка» в data warehouse — это контролируемая денормализация.

Производительность и оптимизация

Когда таблица вырастает до миллионов строк, наивные запросы начинают тормозить. Первый инструмент диагностики — EXPLAIN ANALYZE: он показывает, какой план выбрал оптимизатор, сколько строк просканировал и где узкое место.

Типичные антипаттерны:

  • SELECT * вместо конкретных столбцов — читает больше данных, чем нужно
  • Отсутствие индекса на столбцах в WHERE и JOIN — приводит к полному сканированию таблицы (Seq Scan)
  • Функции на индексированных столбцах: WHERE UPPER(email) = ... — индекс не используется
  • N+1 запросы из ORM — 1 запрос за список + N запросов за детали каждой записи

Индексы — главный способ ускорения. B-tree индекс (по умолчанию) подходит для большинства задач: точные совпадения, диапазоны, сортировка. PostgreSQL также поддерживает GiST (геоданные), GIN (полнотекстовый поиск, JSONB) и BRIN (временные ряды).

Глубокий разбор типов индексов и их применения — в нашей статье об индексах PostgreSQL.

Безопасность: SQL-инъекции

SQL-инъекция — одна из самых опасных уязвимостей веб-приложений, стабильно входящая в OWASP Top 10. Суть: если пользовательский ввод подставляется в запрос без обработки, злоумышленник может изменить логику запроса.

Классический пример — форма логина:

			-- Опасно: конкатенация строк
query = "SELECT * FROM users WHERE email='" + email + "' AND password='" + password + "'"

-- Если ввести в поле email: ' OR 1=1 --
-- Запрос превратится в:
SELECT * FROM users WHERE email='' OR 1=1 --' AND password=''
-- Условие OR 1=1 всегда истинно → доступ ко всем записям
		

Защита проста и надёжна — параметризованные запросы (prepared statements):

			# Python + psycopg2
cursor.execute(
    "SELECT * FROM users WHERE email = %s",
    (email,)
)

# ORM (SQLAlchemy) — параметризация встроена
User.query.filter_by(email=email).first()
		

Пароли в реальных приложениях никогда не хранят и не сравнивают в открытом виде — их хешируют (bcrypt, argon2), а проверку выполняет код приложения, не SQL-запрос.

При использовании ORM (SQLAlchemy, Django ORM, Prisma) параметризация происходит автоматически. Если пишете raw SQL — никогда не вставляйте пользовательский ввод через конкатенацию строк или f-строки.

Управление доступом: GRANT и REVOKE

Вторая линия защиты — принцип минимальных привилегий. Приложению не нужен суперпользователь базы данных:

			-- Роль для чтения (аналитики, отчёты)
CREATE ROLE analyst LOGIN PASSWORD 'secure_pass';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO analyst;

-- Роль для приложения (чтение + запись, без удаления)
CREATE ROLE app_service LOGIN PASSWORD 'secure_pass';
GRANT SELECT, INSERT, UPDATE ON orders, customers TO app_service;
-- Без DELETE и без доступа к users — минимум привилегий
		

REVOKE отзывает права. В PostgreSQL также доступна Row-Level Security (RLS) — ограничение видимости строк в зависимости от роли: каждый менеджер видит только своих клиентов.

Современный SQL: JSON, диалекты и стандарт SQL:2023

SQL — не замороженный язык из 80-х. Стандарт активно развивается, и последняя версия SQL:2023 (опубликована в июне 2023) принесла два крупных нововведения:

  • SQL/JSON — стандартизированные функции для работы с JSON прямо в SQL-запросах. PostgreSQL поддерживает JSONB с 2014 года, а теперь аналогичные возможности появляются и в других СУБД
  • SQL/PGQ (Property Graph Queries) — графовые запросы внутри SQL. Можно искать пути и паттерны в связанных данных без отдельной графовой базы

На практике каждая СУБД имеет свой диалект:

  • PostgreSQL — PL/pgSQL, JSONB, массивы, расширения (PostGIS, pg_trgm). Ближе всего к стандарту
  • MySQL — оконные функции появились поздно — только в версии 8.0 (2018), LIMIT вместо FETCH FIRST
  • T-SQL (Microsoft SQL Server) — TOP вместо LIMIT, IDENTITY вместо SERIAL, мощные CTE
  • PL/SQL (Oracle) — ROWNUM, CONNECT BY для иерархий, пакеты (packages)
  • Cloud SQL — BigQuery, Redshift, Snowflake имеют свои расширения, но базовый SQL везде одинаков

Хорошая новость: базовый синтаксис (SELECT, JOIN, GROUP BY, оконные функции) одинаков во всех диалектах. Освоив стандартный SQL на PostgreSQL, вы легко перейдёте на любую другую СУБД.

PostgreSQL и MySQL

PostgreSQL

PostgreSQL — самая популярная реляционная СУБД для новых проектов. Полная поддержка SQL-стандарта, JSONB для полуструктурированных данных, расширения (PostGIS для геоданных, pg_trgm для нечёткого поиска), продвинутая система типов и отличная производительность.

15 самых полезных команд PostgreSQL — от размера базы до профилирования запросов — в нашей подборке. А для оптимизации больших таблиц — разбор индексов PostgreSQL.

MySQL

MySQL — одна из старейших популярных open-source СУБД, движок WordPress и множества legacy-систем. Проще в настройке, но имеет подводные камни: неявное приведение типов, особенности GROUP BY, различия между InnoDB и MyISAM.

Самые частые ошибки — от кодировок до потери данных — в нашей статье о типичных ошибках MySQL.

Выбор СУБД: SQL vs NoSQL

SQLite — для встраиваемых сценариев: мобильные приложения, Electron, edge computing, прототипы (вся база в одном файле). MySQL — проверенный выбор для веб-приложений, на нём работают GitHub и Booking.com. PostgreSQL — универсальный вариант для новых проектов, от стартапов до enterprise. Детальное сравнение с бенчмарками — в нашем обзоре трёх СУБД.

Когда данные неструктурированные или нужна горизонтальная масштабируемость, рассмотрите NoSQL: MongoDB (документы), Redis (ключ-значение), Cassandra (колонки), Neo4j (графы). Подробнее — в статье о моделях баз данных.

SQL на собеседованиях

SQL-вопросы — обязательная часть собеседований для бэкенд-разработчиков, аналитиков и дата-инженеров. Типичный формат: дают схему из 2–3 таблиц и просят написать запрос. Темы: JOIN-ы, GROUP BY, оконные функции, подзапросы, нормализация.

Ключ к успеху — практика на реальных задачах. Интервьюеры оценивают умение декомпозировать задачу, выбрать правильный тип JOIN и грамотно обработать NULL.

27 самых распространённых вопросов с ответами — в нашей подборке. Для практики — 5 заданий с реальных собеседований с разбором решений.

Частые вопросы
1
Какой диалект SQL учить первым?

Стандартный SQL — он одинаков на 90% во всех СУБД. Для практики лучше PostgreSQL: ближе к стандарту и наиболее востребован. Специфику MySQL или SQLite освоите за пару дней.

2
PostgreSQL или MySQL — что выбрать для нового проекта?

PostgreSQL — если важна корректность, расширяемость и работа со сложными типами (JSON, массивы, геоданные). MySQL — если нужна простота и команда уже знает его. Для новых проектов в 2026 чаще выбирают PostgreSQL.

3
Сколько времени нужно, чтобы выучить SQL?

Базовые запросы (SELECT, WHERE, JOIN, GROUP BY) — 2–3 недели ежедневной практики. Уверенный средний уровень (подзапросы, оконные функции, оптимизация) — 2–3 месяца. Экспертный уровень (планы выполнения, партиционирование, администрирование) — от полугода реального опыта.

4
Чем отличаются WHERE и HAVING?

WHERE фильтрует строки до группировки, HAVING — после. Поэтому в HAVING можно использовать агрегатные функции (COUNT, SUM, AVG), а в WHERE — нельзя. Пример: WHERE salary > 100000 фильтрует отдельных сотрудников, HAVING AVG(salary) > 100000 фильтрует целые отделы.

5
Что такое CTE и зачем он нужен?

CTE (Common Table Expression) — именованный подзапрос в конструкции WITH. Делает сложные запросы читаемыми, позволяет переиспользовать промежуточные результаты, а рекурсивные CTE обходят деревья и графы. Доступен во всех современных СУБД.

6
Как защититься от SQL-инъекций?

Использовать параметризованные запросы (prepared statements) вместо конкатенации строк. Если работаете через ORM — защита встроена. Если пишете raw SQL — никогда не вставляйте пользовательский ввод через f-строки или string formatting.

7
SQL устареет?

Нет. SQL существует с 1974 года и набирает обороты. Даже NoSQL-базы добавляют SQL-подобный синтаксис (CQL в Cassandra, N1QL в Couchbase). Новые инструменты (dbt, Malloy) строятся поверх SQL. ИИ-помощники генерируют SQL, но проверять и понимать его должен человек.

Куда двигаться дальше

SQL — это фундамент, но не потолок. Направления для роста:

  1. Администрирование БД — репликация, бэкапы, мониторинг, настройка производительности
  2. Дата-инженерия — ETL-пайплайны, dbt, Airflow, data warehouse (BigQuery, Snowflake)
  3. Аналитика данных — SQL + Python (pandas), визуализация, A/B-тесты
  4. Бэкенд-разработка — ORM (SQLAlchemy, Prisma, GORM), миграции, проектирование схем
  5. Data Science — feature engineering, работа с большими датасетами

Главный совет: практикуйтесь на реальных данных. Поднимите PostgreSQL локально, загрузите публичный датасет и решайте задачи. Ресурсы для старта:

  • SQLBolt — интерактивные уроки SQL в браузере, от нуля
  • PostgreSQL Exercises — задачи на реальной схеме (клуб, бронирования)
  • LeetCode / HackerRank — SQL-задачи для подготовки к собеседованиям
  • Kaggle Datasets — открытые датасеты для импорта в PostgreSQL и экспериментов
Рекомендуем