SQL для начинающих в эпоху ИИ: какие запросы все равно нужно понимать самому

ИИ умеет написать SQL по описанию, но не знает, какие данные вы имели в виду и можно ли менять production. Ошибка в SELECT вернет неверный отчет, а ошибка в UPDATE изменит тысячи строк.

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

SQL работает с таблицами

Реляционная база хранит данные в таблицах. Строка представляет объект, столбец - его свойство.

Возьмем две таблицы:

customers id | name | email orders id | customer_id | status | total | created_at

orders.customer_id связывает заказ с клиентом. Внешний ключ может запретить ссылку на несуществующего клиента.

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

SELECT читает данные

SELECT id, status, total FROM orders;

SELECT перечисляет столбцы, FROM указывает источник.

На этапе обучения избегайте SELECT * в рабочем коде. Явный список показывает контракт и не возвращает новые чувствительные поля после изменения схемы.

В консоли SELECT * иногда удобен для знакомства, но добавляйте LIMIT на большой таблице.

WHERE ограничивает строки

SELECT id, total FROM orders WHERE status = 'paid';

WHERE определяет, какие строки участвуют. Это критическая часть для чтения и записи.

Составные условия:

WHERE status = 'paid' AND created_at >= '2026-08-01';

Понимайте приоритет AND, OR и скобки. Запрос «paid за август или любой дорогой заказ» отличается от «paid, который за август или дорогой».

Попросите ИИ переписать условие словами и приведите три строки-примера.

ORDER BY и LIMIT

Без ORDER BY база не обязана возвращать строки в привычном порядке.

SELECT id, created_at FROM orders ORDER BY created_at DESC LIMIT 20;

Так выбираются 20 последних заказов.

Для стабильной пагинации добавьте второй уникальный ключ сортировки, если даты могут совпасть.

LIMIT защищает интерфейс от огромного ответа, но не исправляет тяжелый запрос автоматически.

JOIN соединяет таблицы

Чтобы показать имя клиента рядом с заказом:

SELECT o.id, c.name, o.total FROM orders AS o JOIN customers AS c ON c.id = o.customer_id;

Условие ON объясняет, какие строки связаны. Если его забыть или написать неверно, получится множество лишних комбинаций.

INNER JOIN возвращает совпавшие строки. LEFT JOIN сохраняет все строки слева и подставляет NULL, если справа совпадения нет.

Выбор зависит от вопроса. Для отчета «все клиенты, включая без заказов» начинайте с customers и используйте LEFT JOIN.

GROUP BY и агрегаты

Чтобы посчитать число и сумму заказов по статусу:

SELECT status, COUNT(*) AS order_count, SUM(total) AS total_amount FROM orders GROUP BY status;

Агрегат сворачивает несколько строк. Проверяйте единицы: total может храниться в копейках, центах или другой минимальной единице.

WHERE фильтрует строки до группировки, HAVING - группы после нее.

Не просите ИИ «посчитать выручку», пока не определили, какие статусы входят, учитываются ли возвраты, налоги и валюта.

NULL не равен пустой строке

NULL означает отсутствие известного значения. Проверка:

WHERE shipped_at IS NULL

Выражение shipped_at = NULL не работает как обычное равенство.

Агрегаты могут по-разному учитывать NULL. COUNT(*) считает строки, COUNT(column) - ненулевые значения столбца.

ИИ часто пишет синтаксически корректный запрос, но смысл отчета меняется из-за NULL. Создайте пример с отсутствующим значением.

INSERT добавляет строку

INSERT INTO customers (name, email) VALUES ('Анна', 'anna@example.com');

Явно перечисляйте столбцы. Не полагайтесь на их физический порядок.

В рабочем приложении данные передаются параметрами через библиотеку, а не вставляются в SQL строковой конкатенацией. Это защищает от SQL injection и ошибок экранирования.

Уникальные ограничения, NOT NULL и внешние ключи должны находиться в базе, а не только в форме.

UPDATE и DELETE требуют двойной проверки

UPDATE orders SET status = 'cancelled' WHERE id = 1042;

Без WHERE изменятся все строки.

Перед записью выполните соответствующий SELECT с тем же условием:

SELECT id, status FROM orders WHERE id = 1042;

Проверьте число строк и текущий статус. Для массовой операции используйте test/staging, backup и транзакцию.

Не выполняйте сгенерированный ИИ DELETE в production только потому, что объяснение выглядит уверенно.

Транзакция объединяет шаги

Транзакция делает несколько изменений одной операцией. PostgreSQL использует BEGIN, COMMIT и ROLLBACK.

BEGIN; UPDATE orders SET status = 'cancelled' WHERE id = 1042; -- проверки ROLLBACK;

Для безопасной репетиции можно открыть транзакцию, выполнить изменение, проверить строки и откатить. Но внешние побочные эффекты, например отправленное письмо, база откатить не может.

После уверенной проверки выполняется COMMIT. Учитывайте блокировки и длительность: нельзя держать транзакцию открытой бесконечно.

Параметры защищают запрос

Плохо:

`SELECT * FROM users WHERE email = '${email}'`

Пользовательская строка становится частью SQL.

Хорошо использовать параметры библиотеки:

SELECT id, email FROM users WHERE email = $1;

Значение передается отдельно. Точный синтаксис зависит от драйвера.

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

Индексы и скорость

Индекс помогает искать и соединять строки по определенным столбцам. Но каждый индекс занимает место и замедляет записи.

Не добавляйте индекс по совету ИИ без измерения. Используйте EXPLAIN и фактический план на похожем объеме данных. Смотрите, какой запрос медленный и сколько строк он обрабатывает.

Индекс на status может быть бесполезен, если значений мало и запрос возвращает большую часть таблицы. Составной индекс зависит от фильтров и порядка столбцов.

Как просить ИИ написать запрос

Дайте схему и вопрос:

PostgreSQL. Таблицы: customers(id bigint PK, name text, email text unique) orders(id bigint PK, customer_id bigint FK, status text, total integer, created_at timestamptz) Нужно получить 20 клиентов с наибольшей суммой paid-заказов за август 2026. total хранится в копейках. Сначала объясни смысл запроса по шагам. Не выполняй его. Укажи, как обрабатываются клиенты без заказов и NULL.

После ответа прочитайте FROM, JOIN, WHERE, GROUP BY, ORDER BY и LIMIT. Для каждой части сформулируйте вопрос, который она решает.

Проверяйте на маленьких данных

Создайте тестовый набор из пяти клиентов и нескольких заказов:

· клиент без заказов;

· paid и cancelled;

· заказ на границе периода;

· одинаковая сумма;

· NULL там, где он допустим.

Вручную посчитайте ожидаемый ответ. Затем выполните запрос в test-базе и сравните.

Генератор случайных данных не заменяет осмысленные границы.

Не давайте агенту широкие права

Для анализа используйте read-only пользователя. Отдельные credentials выдаются миграциям и production-операциям.

Не передавайте дамп с персональными данными в внешний чат. Используйте схему и обезличенный пример.

Если агент запускает SQL через инструмент, включите подтверждение для записи, лимит строк и журнал. Административный ключ не должен быть значением по умолчанию.

Что нужно понимать самому

Новичку достаточно уметь:

1. Прочитать таблицы и связи.

2. Объяснить SELECT, WHERE, JOIN и GROUP BY.

3. Проверить границы даты и NULL.

4. Выполнить SELECT перед UPDATE.

5. Использовать параметры.

6. Отличить test от production.

7. Понимать транзакцию и откат.

8. Проверять план тяжелого запроса.

Остальной синтаксис можно искать по документации.

Практика на одной схеме

Создайте две учебные таблицы: customers и orders. В заказе храните customer_id, сумму, статус и дату. На этой схеме выполните последовательность:

9. выбрать десять последних заказов;

10. отфильтровать только оплаченные;

11. присоединить имя клиента через JOIN;

12. посчитать сумму по каждому клиенту;

13. найти клиентов без заказов;

14. обновить статус одного заказа по точному id;

15. выполнить два связанных изменения в транзакции и откатить их.

Перед каждым запросом сформулируйте ожидаемые строки обычными словами. После выполнения сравните количество и несколько значений. Если результат неожиданно пустой, не добавляйте условия наугад: проверьте типы, NULL, связи и реальные данные.

Читайте план тяжелого запроса

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

Новичку не нужно сразу разбирать каждый тип узла. Начните с вопросов:

· читается ли вся большая таблица;

· используется ли условие по индексированному полю;

· не умножил ли JOIN число строк;

· совпадает ли приблизительное число строк с ожиданием;

· можно ли сузить данные раньше.

Не создавайте индекс на каждое поле по совету ИИ. Индексы ускоряют часть чтения, но занимают место и замедляют запись. Проверяйте реальный частый запрос и измеряйте до и после.

Безопасный маршрут для UPDATE и DELETE

Сначала превратите будущую операцию в SELECT с тем же WHERE. Прочитайте строки и посчитайте их. Затем откройте транзакцию, выполните изменение и снова выберите затронутые данные. Если результат неверный, используйте ROLLBACK.

Для рабочей базы добавьте резервную копию и ограниченную роль. Аккаунт аналитика обычно не должен удалять таблицы или менять всех пользователей. Не подключайте coding agent под владельцем базы.

Если запрос затрагивает деньги, права или историю, проведите review вторым человеком. Условие WHERE синтаксически простое, но его бизнес-смысл может быть ошибочным.

Проверяйте запрос ИИ как гипотезу

Просите модель назвать предположения о схеме и показать, какие строки могут дублироваться. Передавайте CREATE TABLE или описание колонок, а не скриншот части интерфейса. Укажите диалект: PostgreSQL, SQLite и другие базы различаются.

После ответа разберите каждую часть: источники после FROM, условия соединения, фильтры, группировку и сортировку. Если модель использует неизвестную колонку или функцию, вернитесь к официальной документации. Уверенный синтаксис не подтверждает существование поля.

На курсе «Вайбкодинг на максималках» SQL используется внутри приложения вместе с базой, API, правами, Git и деплоем.

ИИ снижает цену написания SQL, но повышает ценность чтения. Начните с безопасного SELECT, проверьте результат на маленьком наборе и только затем переходите к изменениям. Если вы не можете объяснить условие запроса обычными словами, его рано запускать на рабочих данных.

2