SQL — реальные кейсы
Подборка готовых SQL-запросов с построчным разбором — как в галерее Turtle: скопировали код, выполнили, сверили результат с таблицей ниже. Схема — учебный интернет-магазин (клиенты, товары, заказы, позиции чека).
Материал заточен под запросы вроде «sql примеры join», «sql group by sum», «как посчитать сумму заказа sql», «sql выборка where», «лабораторная работа база данных sql», «sql insert update пример» — когда нужен рабочий текст запроса и объяснение, а не только синтаксис из учебника.
Для кого эта статья
| Аудитория | Зачем открыть |
|---|---|
| Школьники | Информатика, лабораторная «таблицы и запросы», подготовка к заданиям с базами |
| Студенты | Курсовой фрагмент с SELECT/JOIN, отчёт с скриншотами из DBeaver или тренажёра |
| Самоучки | Первый SQL после Excel — те же отчёты, но языком запросов |
| Начинающие разработчики | Backend + PostgreSQL, типовые отчёты для админки |
| Аналитики | Быстрый прототип выгрузки перед Pandas |
Как работать с примером (как с кодом Turtle):
- Откройте схему и демо-таблицы — без них цифры в ответе «не сойдутся».
- Скопируйте SQL из блока в тренажёр на этой странице (кнопка «Выполнить») или в
psql/ DBeaver. - Сравните вывод с колонкой «Пример результата» в разделе.
- Прочитайте таблицу «Разбор по строкам» — что делает каждая строка.
- Сделайте «Попробуйте» — одно изменение (
WHERE,JOIN) закрепляет тему лучше, чем перечитывание.
Маршрут с нуля — SQL — о разделе и первые шаги. Тот же тренажёр в теории — SQL — язык. Шпаргалка без разбора — типичные задачи. Таблицы в Python — Pandas, формулы — Excel. PostgreSQL в Docker — compose-стеки. Минимальный CRUD — шаблоны.
Над редактором — чипы-примеры (SELECT, JOIN, GROUP BY, INSERT…). Нажмите чип, затем разберите тот же текст по таблице в статье.
Краткий указатель — что ищут в Google
| Раздел | Типичный запрос (RU / EN) |
|---|---|
| Как читать запрос | как читать sql запрос, sql синтаксис для начинающих |
| Схема магазина | sql схема базы данных пример, foreign key sql |
| Каркас SELECT | sql select from where, структура sql запроса |
| Стартовые выборки | sql выборка where, sql сортировка order by |
| 1. Сумма заказа | sql sum join, сумма заказа sql, group by sql пример |
| 2. Топ товаров | sql топ товаров, count group by |
| 3. Клиенты без заказов | left join sql пример, клиенты без заказов sql |
| 4. Склад | sql where остаток, выборка товаров sql |
| 5. Статусы | sql count group by, средний чек sql |
| 6. JOIN справочник | sql inner join две таблицы, sql join example |
| 7. DML | sql insert пример, sql update set |
| 8. Ошибки | sql group by error, ambiguous column sql |
Как читать SQL-запрос по частям
Любой запрос читают сверху вниз как инструкцию для СУБД. Сначала «откуда взять строки», потом «что отфильтровать», потом «что показать».
Пример одной фразы:
SELECT name FROM products WHERE price > 500;
| Часть | Роль | Аналог в Excel |
|---|---|---|
SELECT name | Какие столбцы попадут в ответ | Выделили столбец «Название» |
FROM products | Из какой таблицы | Лист «Товары» |
WHERE price > 500 | Какие строки оставить | Автофильтр «цена > 500» |
; | Конец команды (в тренажёре можно без неё) | — |
Типы команд в этой статье:
| Команда | Зачем | Меняет данные? |
|---|---|---|
SELECT | Прочитать, посчитать отчёт | Нет |
INSERT | Добавить строки | Да |
UPDATE | Изменить строки | Да |
DELETE | Удалить строки | Да |
Схема учебного магазина
Четыре таблицы — типичный интернет-магазин. Одна строка в order_items — одна позиция в чеке (как строка в кассовом чеке).
| Таблица | Роль | Ключевые столбцы |
|---|---|---|
customers | Покупатели | customer_id, full_name, email, city |
products | Каталог | product_id, name, price, category, stock_qty |
orders | Заказ | order_id, customer_id, order_date, status |
order_items | Позиция чека | order_id, product_id, quantity, unit_price |
Зачем unit_price в позиции: в чеке фиксируют цену на момент покупки. Поле products.price могли изменить завтра — сумма старого заказа от этого не меняется.
В тренажёре также есть users и cities — раздел 6.
На PostgreSQL те же таблицы в схеме shop_data — пишут shop_data.customers. В браузерном тренажёре префикс не нужен.
Демо-данные — сверяйте с ними ответы
Выполните в тренажёре SELECT * FROM products; — увидите те же строки.
products (фрагмент):
| product_id | name | price | category | stock_qty |
|---|---|---|---|---|
| 1 | Алгоритмы | 799 | Книги | 15 |
| 2 | SQL для профессионалов | 1299 | Книги | 0 |
| 3 | USB-кабель | 299 | Аксессуары | 42 |
| 5 | Блокнот | 99 | Канцелярия | 120 |
orders:
| order_id | customer_id | order_date | status |
|---|---|---|---|
| 1 | 1 (Анна) | 2024-05-01 | completed |
| 2 | 1 (Анна) | 2024-05-10 | new |
| 3 | 2 (Борис) | 2024-05-12 | processing |
| 4 | 3 (Елена) | 2024-05-15 | completed |
order_items — отсюда берутся суммы в примерах:
| order_id | product_id | quantity | unit_price | Строка чека |
|---|---|---|---|---|
| 1 | 1 | 1 | 799 | 799 |
| 1 | 3 | 2 | 299 | 598 |
| 2 | 2 | 1 | 1299 | 1299 |
| 3 | 4 | 1 | 1499 | 1499 |
| 4 | 5 | 3 | 99 | 297 |
Суммы заказов вручную (для проверки GROUP BY):
| order_id | Расчёт | order_total |
|---|---|---|
| 1 | 799 + 2×299 | 1397 |
| 2 | 1299 | 1299 |
| 3 | 1499 | 1499 |
| 4 | 3×99 | 297 |
Основы — от задачи к запросу
Перед кодом сформулируйте задачу словами:
- Какие таблицы нужны? (клиенты, заказы, позиции…)
- Как они связаны? (
customer_id,order_id…) - Какой фильтр? (статус, дата, город…)
- Что в ответе? (список имён, сумма, количество…)
- Сортировка? (сначала самые дорогие, старые заказы первыми…)
На лабораторной и собеседовании эту цепочку часто просят проговорить до написания SQL.
Основы SELECT
Обязательный каркас
Минимальная программа в мире SQL — один SELECT. Полный «скелет» отчёта:
SELECT столбцы_или_выражения -- ЧТО показать
FROM таблица -- ОТКУДА строки
JOIN другая ON связь -- ДОБАВИТЬ связанные строки
WHERE условие_на_строки -- ФИЛЬТР до группировки
GROUP BY столбцы_группы -- СВЕРНУТЬ в группы
HAVING условие_на_группы -- ФИЛЬТР после группировки
ORDER BY сортировка -- ПОРЯДОК строк в ответе
LIMIT число; -- СКОЛЬКО строк вернуть
Порядок выполнения СУБД (упрощённо — для понимания, не для заучивания порядка написания):
| Шаг | Клауза | Что происходит |
|---|---|---|
| 1 | FROM / JOIN | Склеивают таблицы; получается длинный список строк |
| 2 | WHERE | Отбрасывают лишние строки |
| 3 | GROUP BY | Объединяют строки в группы (например, по order_id) |
| 4 | HAVING | Отбрасывают целые группы |
| 5 | SELECT | Считают SUM, COUNT, выводят столбцы |
| 6 | ORDER BY / LIMIT | Сортируют и обрезают результат |
Теория — принципы SQL-движка.
Шаблон — клиент и его завершённые заказы
Задача: список имён и дат только по заказам со статусом completed.
SELECT
c.full_name,
o.order_id,
o.order_date
FROM customers c
INNER JOIN orders o ON o.customer_id = c.customer_id
WHERE o.status = 'completed'
ORDER BY o.order_date DESC;
Разбор по строкам:
| Строка | Код | Смысл |
|---|---|---|
| 1–4 | SELECT c.full_name, o.order_id, o.order_date | Три столбца в результате; префикс c. / o. — из какой таблицы столбец |
| 5 | FROM customers c | Главная таблица — клиенты; c — короткий псевдоним |
| 6 | INNER JOIN orders o ON o.customer_id = c.customer_id | К каждому клиенту подтянуть только его заказы по совпадению id |
| 7 | WHERE o.status = 'completed' | Оставить строки, где статус заказа — завершён |
| 8 | ORDER BY o.order_date DESC | Сначала свежие даты (DESC — по убыванию) |
Пример результата (смысл):
| full_name | order_id | order_date |
|---|---|---|
| Анна Иванова | 1 | 2024-05-01 |
| Елена Смирнова | 4 | 2024-05-15 |
Заказ Анны №2 (new) и заказ Бориса не попадут — фильтр completed.
Частая ошибка: писать status = completed без кавычек — СУБД воспримет completed как имя столбца, будет ошибка.
Попробуйте: замените INNER JOIN на LEFT JOIN — появятся ли клиенты без заказов? (да, с NULL в столбцах заказа).
Стартовые выборки
Простые запросы без JOIN — как первый квадрат в Turtle: одна таблица, один навык.
Все товары — проверка связи с БД
Задача: убедиться, что запрос выполняется (аналог print("Hello")).
SELECT * FROM products;
| Строка | Смысл |
|---|---|
SELECT * | Все столбцы всех строк |
FROM products | Таблица каталога |
Попробуйте: SELECT name, price FROM products; — только два столбца.
Каталог дороже 500 ₽
Задача: витрина «дорогие товары» для сайта.
SELECT product_id, name, price, category
FROM products
WHERE price > 500
ORDER BY price DESC;
Разбор по строкам:
| Строка | Код | Смысл |
|---|---|---|
| 1 | SELECT product_id, name, price, category | Явный список столбцов — лучше, чем *, в реальных проектах |
| 2 | FROM products | Источник — каталог |
| 3 | WHERE price > 500 | Число без кавычек; сравнение столбца с константой |
| 4 | ORDER BY price DESC | Сортировка по убыванию цены |
Пример результата:
| product_id | name | price | category |
|---|---|---|---|
| 2 | SQL для профессионалов | 1299 | Книги |
| 4 | Power bank | 1499 | Аксессуары |
| 1 | Алгоритмы | 799 | Книги |
Блокнот (99) и USB-кабель (299) отфильтрованы условием > 500.
Попробуйте: AND category = 'Книги' в той же строке WHERE.
Клиенты из Москвы
Задача: выгрузка для региональной рассылки.
SELECT full_name, email, city
FROM customers
WHERE city = 'Москва';
Разбор:
| Строка | Смысл |
|---|---|
WHERE city = 'Москва' | Текст в одинарных кавычках; пробел и регистр должны совпасть с данными |
Без JOIN | Одна таблица — проще всего для первой лабораторной |
Пример результата: Анна Иванова и Елена Смирнова (в демо у обеих город Москва).
Частая ошибка: WHERE city = Москва — СУБД ищет столбец с именем Москва.
Заказы за май 2024
Задача: отчёт за календарный месяц.
SELECT order_id, customer_id, order_date, status
FROM orders
WHERE order_date >= '2024-05-01'
AND order_date < '2024-06-01';
Разбор:
| Строка | Смысл |
|---|---|
>= '2024-05-01' | С 1 мая включительно |
AND order_date < '2024-06-01' | До 1 июня не включая — весь май |
AND | Оба условия должны выполняться |
Так задают диапазон дат в SQL чаще, чем BETWEEN (с BETWEEN легко ошибиться с последним днём месяца).
Пример результата: все четыре демо-заказа (даты с 2024-05-01 по 2024-05-15).
Попробуйте: оставьте только status = 'new' — останется заказ №2.
Поиск по подстроке в названии (LIKE)
Задача: найти товары со словом «кабель» в имени.
SELECT name, price
FROM products
WHERE name LIKE '%кабель%';
| Часть | Смысл |
|---|---|
LIKE | Сравнение с шаблоном, не с точным равенством |
% | Любое количество любых символов до и после |
'%кабель%' | «кабель» где угодно внутри строки |
Пример результата: USB-кабель.
В PostgreSQL для регистронезависимого поиска — ILIKE '%кабель%'.
Примеры из практики
Кейсы ниже — типичные задания лабораторных, стажировок и джуниор-позиций. Каждый блок: задача → код → разбор по строкам → пример результата → попробуйте.
Все запросы проверены в тренажёре на этой странице.
1. Выручка и сумма заказа
1.1. Сумма каждого заказа (GROUP BY + SUM + JOIN)
Задача: для каждого order_id посчитать итог чека — сумма quantity * unit_price по всем позициям.
Какие таблицы: orders + order_items (без клиентов — только чеки).
SELECT
o.order_id,
o.order_date,
o.status,
SUM(oi.quantity * oi.unit_price) AS order_total
FROM orders o
INNER JOIN order_items oi ON oi.order_id = o.order_id
GROUP BY o.order_id, o.order_date, o.status
ORDER BY order_total DESC;
Разбор по строкам:
| Строка | Код | Смысл |
|---|---|---|
| 1–5 | SELECT … SUM(oi.quantity * oi.unit_price) AS order_total | Для каждой группы сложить произведения «кол-во × цена в чеке» |
| 5 | SUM(...) | Агрегатная функция — одно число на группу |
| 5 | AS order_total | Имя столбца в результате (удобно в отчёте и API) |
| 6 | FROM orders o | Заказы — «хребет» отчёта |
| 7 | INNER JOIN order_items oi ON oi.order_id = o.order_id | Приклеить строки чека к заказу |
| 8 | GROUP BY o.order_id, o.order_date, o.status | Одна группа = один заказ; в PostgreSQL все неагрегированные столбцы из SELECT должны быть здесь |
| 9 | ORDER BY order_total DESC | Сначала самые крупные чеки |
Почему нельзя забыть GROUP BY: без него SUM попытается сложить все позиции всех заказов в одно число.
Пример результата (сверка с таблицей сумм выше):
| order_id | order_date | status | order_total |
|---|---|---|---|
| 1 | 2024-05-01 | completed | 1397 |
| 3 | 2024-05-12 | processing | 1499 |
| 2 | 2024-05-10 | new | 1299 |
| 4 | 2024-05-15 | completed | 297 |
Порядок строк после ORDER BY order_total DESC именно такой (1397 сверху).
Связь с Excel: на листе «Позиции» столбец «Сумма строки» = quantity * price, затем сводная таблица по order_id с полем «Сумма». В Pandas — df.groupby('order_id').apply(...), см. 1113.
Попробуйте: добавьте WHERE o.status = 'completed' перед GROUP BY — останутся только заказы 1 и 4.
1.2. Выручка по клиентам за всё время
Задача: кто сколько потратил — для CRM, бонусов, «топ покупателей».
Какие таблицы: цепочка customers → orders → order_items.
SELECT
c.customer_id,
c.full_name,
SUM(oi.quantity * oi.unit_price) AS revenue
FROM customers c
INNER JOIN orders o ON o.customer_id = c.customer_id
INNER JOIN order_items oi ON oi.order_id = o.order_id
GROUP BY c.customer_id, c.full_name
ORDER BY revenue DESC;
Разбор по строкам:
| Строка | Смысл |
|---|---|
FROM customers c | Старт с покупателей — в отчёте будет каждый клиент, у кого есть хотя бы одна позиция в заказе |
Первый JOIN orders | Подтянуть заказы клиента |
Второй JOIN order_items | Подтянуть позиции этих заказов |
GROUP BY c.customer_id, c.full_name | Свернуть все позиции всех заказов клиента в одну сумму |
Пример результата (ручная проверка):
| full_name | revenue | Откуда цифра |
|---|---|---|
| Анна Иванова | 2696 | заказ 1 (1397) + заказ 2 (1299) |
| Борис Петров | 1499 | заказ 3 |
| Елена Смирнова | 297 | заказ 4 |
Клиент Дмитрий Козлов (без заказов в демо) не появится — сработал INNER JOIN.
Попробуйте: LEFT JOIN вместо первого JOIN с orders и фильтр — отдельный кейс «Клиенты без заказов».
2. Топ товаров по продажам
2.1. Сколько штук продали (не рубли)
Задача: рейтинг товаров по количеству проданных единиц.
SELECT
p.product_id,
p.name,
SUM(oi.quantity) AS units_sold
FROM products p
INNER JOIN order_items oi ON oi.product_id = p.product_id
GROUP BY p.product_id, p.name
ORDER BY units_sold DESC;
Разбор:
| Строка | Смысл |
|---|---|
SUM(oi.quantity) | Складываем штуки, а не деньги |
INNER JOIN | Товары без продаж в отчёт не попадут |
Пример результата:
| name | units_sold |
|---|---|
| Блокнот | 3 |
| USB-кабель | 2 |
| Алгоритмы, SQL…, Power bank | по 1 |
2.2. Товары, которые ни разу не продавали
Задача: кандидаты на распродажу или снятие с витрины.
SELECT
p.product_id,
p.name,
p.stock_qty
FROM products p
LEFT JOIN order_items oi ON oi.product_id = p.product_id
WHERE oi.order_item_id IS NULL;
Разбор по строкам:
| Строка | Смысл |
|---|---|
LEFT JOIN | Взять все товары из products |
WHERE oi.order_item_id IS NULL | Оставить только те, для кого не нашлось строки в order_items |
Проверка по order_item_id | Любой столбец из правой таблицы будет NULL, если совпадения не было |
В текущих демо-данных все 5 товаров хотя бы раз продавались — результат пустой. Это нормально: запрос верный, данных под условие нет.
Попробуйте: выполните INSERT нового товара без заказов (раздел 7) и повторите запрос.
2.3. Топ с нулевыми продажами (LEFT JOIN + COALESCE)
Задача: в одной таблице — и проданные, и непроданные; у непроданных — 0.
SELECT
p.name,
COALESCE(SUM(oi.quantity), 0) AS units_sold
FROM products p
LEFT JOIN order_items oi ON oi.product_id = p.product_id
GROUP BY p.product_id, p.name
ORDER BY units_sold DESC;
| Часть | Смысл |
|---|---|
LEFT JOIN | Все товары остаются в группах |
COALESCE(SUM(...), 0) | SUM по пустой группе даёт NULL — заменяем на 0 |
3. Клиенты без заказов
3.1. LEFT JOIN + IS NULL
Задача: кому отправить письмо «вы забыли корзину».
SELECT c.customer_id, c.full_name, c.email
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.customer_id
WHERE o.order_id IS NULL;
Разбор:
| Строка | Смысл |
|---|---|
LEFT JOIN orders | Все клиенты + их заказы, если есть |
WHERE o.order_id IS NULL | Строки, где заказ не подтянулся — у клиента 0 заказов |
Попробуйте: INSERT INTO customers ... без заказов для нового id — увидите строку в результате.
3.2. NOT EXISTS (часто на экзаменах)
SELECT c.customer_id, c.full_name
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.customer_id
);
| Часть | Смысл |
|---|---|
EXISTS (подзапрос) | Истина, если подзапрос вернул хотя бы одну строку |
NOT EXISTS | Истина, если заказов нет |
SELECT 1 | В подзапросе важен факт наличия строки, а не значение столбца |
Теория — подзапросы и EXISTS.
3.3. Email для рассылки
SELECT full_name, email
FROM customers
WHERE email IS NOT NULL;
Разбор:
| Неправильно | Правильно |
|---|---|
email = NULL | email IS NULL |
email != NULL | email IS NOT NULL |
Пример: Дмитрий Козлов с email = NULL не попадёт в рассылку.
4. Склад — нулевой и низкий остаток
4.1. Нет на складе
SELECT product_id, name, category, stock_qty
FROM products
WHERE stock_qty = 0
ORDER BY category, name;
Пример результата: «SQL для профессионалов», stock_qty = 0.
4.2. Мало на складе (меньше 10, но больше 0)
SELECT name, category, stock_qty
FROM products
WHERE stock_qty > 0 AND stock_qty < 10
ORDER BY stock_qty ASC;
Разбор: AND объединяет два условия; ORDER BY stock_qty ASC — сначала критичные остатки (Power bank, 8 шт.).
5. Заказы по статусу
5.1. Сколько заказов в каждом статусе
SELECT status, COUNT(*) AS cnt
FROM orders
GROUP BY status
ORDER BY cnt DESC;
Разбор:
| Строка | Смысл |
|---|---|
COUNT(*) | Число строк в группе = число заказов |
GROUP BY status | Группа = одно значение статуса |
Пример результата: по одному заказу в статусах completed, new, processing (cnt = 1), если в демо по одному заказу каждого типа.
5.2. Очередь «новых» заказов (FIFO)
SELECT o.order_id, c.full_name, o.order_date
FROM orders o
INNER JOIN customers c ON c.customer_id = o.customer_id
WHERE o.status = 'new'
ORDER BY o.order_date ASC;
Пример: заказ №2, Анна Иванова, 2024-05-10.
5.3. Средний чек по завершённым заказам
Задача: одно число — средняя сумма завершённого чека.
Идея в два шага: (1) посчитать сумму каждого заказа; (2) взять среднее от этих сумм.
SELECT AVG(order_total) AS avg_check
FROM (
SELECT
o.order_id,
SUM(oi.quantity * oi.unit_price) AS order_total
FROM orders o
INNER JOIN order_items oi ON oi.order_id = o.order_id
WHERE o.status = 'completed'
GROUP BY o.order_id
) t;
Разбор:
| Уровень | Смысл |
|---|---|
Внутренний SELECT | Таблица из двух строк: заказы 1 (1397) и 4 (297) |
WHERE o.status = 'completed' | Только завершённые до группировки |
Внешний AVG(order_total) | (1397 + 297) / 2 = 847 |
t | Псевдоним подзапроса в FROM — обязателен |
В PostgreSQL то же читается проще с WITH — CTE.
6. Сотрудники и справочник городов
Учебный кейс «факт + справочник» — как orders + customers, но про HR.
6.1. INNER JOIN — только с заполненным городом
SELECT u.name AS employee, c.name AS city_name, c.region
FROM users u
INNER JOIN cities c ON u.city_id = c.id
ORDER BY c.region, u.name;
Разбор:
| Строка | Смысл |
|---|---|
u.city_id = c.id | Условие связи: внешний ключ → первичный ключ справочника |
AS employee | Псевдоним столбца в результате |
u, c | Псевдонимы таблиц |
6.2. LEFT JOIN — показать всех, даже без города
SELECT u.name, c.name AS city_name
FROM users u
LEFT JOIN cities c ON u.city_id = c.id;
Если у сотрудника city_id пустой — в city_name будет NULL.
6.3. UNION — список городов из двух источников
SELECT city AS place FROM customers
UNION
SELECT city AS place FROM users;
| Команда | Смысл |
|---|---|
UNION | Объединить результаты и убрать дубликаты |
UNION ALL | Объединить с дубликатами (быстрее, если дубли допустимы) |
| Одинаковые имена столбцов | В обеих частях первый столбец логически «место» |
7. Изменение данных (DML)
В тренажёре команды меняют демо-базу до кнопки «Сброс». На сервере используют транзакции.
7.1. Пополнить склад
UPDATE products
SET stock_qty = stock_qty + 50
WHERE category = 'Книги';
Разбор по строкам:
| Строка | Смысл |
|---|---|
UPDATE products | Какую таблицу меняем |
SET stock_qty = stock_qty + 50 | Новое значение = старое + 50 (атомарно на сервере) |
WHERE category = 'Книги' | Только книги; без WHERE обновятся все строки |
После выполнения у «SQL для профессионалов» остаток станет 50 (был 0).
7.2. Новый товар
INSERT INTO products (name, price, category, stock_qty)
VALUES ('Наушники', 2499, 'Аксессуары', 10);
| Строка | Смысл |
|---|---|
Список в скобках после products | В какие столбцы пишем (остальные — default или NULL) |
VALUES (...) | Одна новая строка |
Проверка:
SELECT * FROM products WHERE name = 'Наушники';
7.3. Сменить статус заказов
UPDATE orders
SET status = 'cancelled'
WHERE status = 'new';
Пример: отменится заказ №2 (единственный new в демо).
7.4. Удаление (осторожно)
DELETE FROM orders WHERE status = 'new';
DELETE FROM orders удалит все заказы. В тренажёре — «Сброс»; на сервере — бэкап, см. резервное копирование.
7.5. Безопасный ввод из приложения (SQL-инъекции)
Нельзя собирать запрос так:
# ОПАСНО — так не делают
query = f"SELECT * FROM customers WHERE email = '{user_input}'"
Нужно передавать значения отдельно:
cur.execute(
"SELECT * FROM customers WHERE email = %s",
(user_email,),
)
await pool.query('SELECT * FROM customers WHERE email = $1', [userEmail]);
СУБД отделит код запроса от данных. Подробнее — SQL-инъекции.
8. Частые ошибки
| Симптом | Причина | Что сделать |
|---|---|---|
column must appear in GROUP BY | В SELECT столбец без агрегата, его нет в GROUP BY | Добавить в GROUP BY или MAX(столбец) |
ambiguous column | id есть в двух таблицах | Писать c.customer_id, o.order_id |
| Пустой отчёт при JOIN | Стоит INNER вместо LEFT | Поменять тип JOIN или проверить ключи в ON |
email = NULL не работает | Сравнение с NULL | Только IS NULL / IS NOT NULL |
| Одна гигантская сумма | Забыли GROUP BY order_id | Группировать по заказу |
| Строк дублируется в 2× | Лишний JOIN | Убрать лишнюю таблицу или уточнить ON |
В тренажёре ошибка на WITH | Движок тренажёра проще сервера | Выполнить в PostgreSQL — 111 |
| Цифры не как в статье | Данные меняли INSERT/DELETE | «Сброс» в тренажёре |
Шпаргалка одной страницей
| Нужно | Шаблон |
|---|---|
| Все строки таблицы | SELECT * FROM имя; |
| Фильтр | WHERE столбец = значение |
| Диапазон дат | WHERE d >= '2024-05-01' AND d < '2024-06-01' |
| Связать 2 таблицы | FROM a JOIN b ON a.id = b.a_id |
| Сумма по группам | SELECT ключ, SUM(…) FROM … GROUP BY ключ |
| Клиенты без заказов | LEFT JOIN + WHERE заказ.id IS NULL |
| Добавить строку | INSERT INTO t (cols) VALUES (…); |
| Изменить | UPDATE t SET col = … WHERE …; |
Что дальше
| Тема | Куда идти |
|---|---|
| JOIN, CTE, окна | дорожная карта SQL |
| Тот же магазин на сервере | практикум shop_data |
| Рецепты без построчного разбора | шпаргалка 885 |
| PostgreSQL в Docker | compose-стеки |
| Таблицы в Python | Pandas — примеры |
| Визуальные примеры кода | Turtle |
Скопируйте один кейс, выполните в тренажёре, измените одно условие в WHERE — так SQL запоминается так же, как короткие программы на Turtle: руками, а не только чтением.
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Практическая карта типовых IT-задач: термины, пошаговое внедрение, проверка качества и типичные ошибки. Простой консольный чат на C# — учебное приложение с сокетами: TCP между клиентом и сервером, многопоточность и обмен сообщениями в консоли. Примеры вёрстки на HTML и CSS с разбором: центрирование, Flexbox, Grid, формы, шапка, подвал и адаптив для учебы и портфолио. Перед началом работы обязательно изучите главу Turtle . Галерея 3D-фигур на Panda3D — карточки, куб, пирамида, сфера, сетки и составные сцены; код для локального запуска. Готовые docker-compose.yml с разбором каждой строки — nginx, PostgreSQL, Redis, WordPress, MongoDB. Примеры для школьников и студентов: postgres example, поднять базу локально, app + db. Примеры nginx.conf для статики, reverse proxy, React/Vue SPA, PHP, SSL и балансировки — построчный разбор директив, проверка curl и типичные ошибки для лабораторных и VPS. dockerfile example — 10 готовых Dockerfile с построчным разбором: node, python, golang, react nginx, spring boot, php, dotnet. Для студентов, лабораторных и docker build с нуля. PromQL example — готовые запросы Prometheus и Grafana с построчным разбором: up, rate, node_exporter cpu, memory, disk, http_requests_total, histogram_quantile p99, алерты. Для студентов, лабораторных и devops docker compose. Готовые манифесты Kubernetes с разбором каждой строки — Pod, Deployment, Service, ConfigMap, Secret, Ingress. Примеры для Minikube, kind и kubectl apply. Примеры графиков Matplotlib на Python для школьников и студентов — sin, cos, парабола, столбцы, scatter, гистограмма, подграфики; код с подробным разбором. Примеры pandas на Python для школьников и студентов — DataFrame, фильтрация, groupby, очистка, merge, сводные таблицы и экспорт; код с подробным разбором каждой строки.Готовые решения
Простой консольный чат на CSharp
HTML + CSS — готовые макеты
Примеры фигур Turtle на Python
Примеры фигур Panda3D на Python
Docker Compose — готовые стеки
Nginx — конфиги под задачу
Dockerfile — 10 типовых образов
Prometheus + Grafana — запросы
Kubernetes YAML — минимальные манифесты
Matplotlib — графики
Pandas — типовые операции