ИИ для SQL-запросов: генерация и проверка без хаоса в 2026

Обновлено 25 июня 2026 года: я переписал материал под текущую практику работы с языковыми моделями, добавил двухэтапную проверку SQL, метрики качества и пример тестирования на малой выборке.
SQL редко ломается громко. Чаще он возвращает правдоподобные цифры, и именно это опасно. Нейросеть помогает быстрее собрать запрос, найти синтаксические ошибки, заметить лишние соединения таблиц и предложить план оптимизации. Но я не отдаю ей финальное решение без проверки. Рабочий подход выглядит как короткий конвейер: сформулировать задачу, получить черновик, прогнать его через вторую проверку, протестировать на малом наборе данных, посмотреть план выполнения и только потом переносить в рабочий контур.
Что изменилось в обновлённой версии
Раньше такие статьи часто сводились к совету «попросите нейросеть написать SQL». В 2026 году этого мало. Я обновил материал вокруг проверки результата, потому что именно там теряется больше всего времени: одно неверное условие по дате может испортить отчёт за квартал, а лишнее соединение таблицы превращает запрос на 2 секунды в запрос на 2 минуты.
Модельный кейс: менеджер данных готовил еженедельный отчёт по оплатам 4 часа: 35 минут уходило на уточнение логики, 60 минут на первый вариант запроса, 75 минут на проверку крайних случаев, 45 минут на ускорение, ещё около 25 минут на правки после замечаний аналитика. Нейросеть здесь не заменяет понимание схемы. Она убирает пустую механическую работу: собрать черновик с общими табличными выражениями, перечислить проверки, подсказать индекс или переписать подзапрос через оконную функцию.
Если вы только настраиваете стиль запросов к ИИ, полезно сначала разобрать как формулировать запросы для нейросетей. Для SQL это особенно заметно: плохой промпт даёт красивый, но случайный код, хороший промпт ограничивает модель схемой, диалектом и критериями приёмки.
Где ИИ реально экономит время в SQL
Я делю работу с SQL на 5 зон. В каждой нейросеть полезна по-разному.
| Зона работы | Что делает человек | Что можно поручить ИИ | Типовой риск |
|---|---|---|---|
| Постановка задачи | Уточняет бизнес-правило | Переформулирует задачу в технические условия | Потеря нюанса, например статуса возврата |
| Первый запрос | Знает схему и связи | Пишет черновик SQL по описанию таблиц | Выдуманная колонка или неверный диалект |
| Проверка | Сравнивает с ожидаемым результатом | Ищет ошибки, NULL, дубли, границы дат | Уверенный неправильный вывод |
| Оптимизация | Смотрит план выполнения | Предлагает индексы, CTE, оконные функции | Индекс ускорит чтение, но замедлит запись |
| Документация | Объясняет запрос коллегам | Пишет комментарии и краткое описание | Слишком общие пояснения |
На практике самый сильный эффект появляется не на генерации, а на повторяемой проверке. Запрос на 80 строк легко прочитать один раз. Проблема начинается, когда нужно проверить 12 условий: часовой пояс, отменённые оплаты, тестовые аккаунты, частичные возвраты, дубли в событиях, пустые значения, закрытый период, витрина с задержкой обновления. Нейросеть быстро превращает этот список в чек-лист и тестовые случаи.
В SoftChat удобно вести такую работу в диалоге: ответы отображаются с форматированием Markdown, кодом и таблицами, а история разговоров хранится в рамках организации. Для повторяемых задач я использую шаблоны промптов, например отдельную заготовку для генерации SQL и отдельную для ревью. Если черновик запроса к модели получился слишком расплывчатым, перед отправкой можно воспользоваться улучшением запроса и принять или отклонить предложенную правку.
Шаг 1. Дайте модели схему, диалект и критерии приёмки
Запрос «напиши SQL для отчёта по оплатам» почти бесполезен. Модель не знает, как в вашей базе называются таблицы, в каком поле лежит статус, что считать оплатой и как обрабатывать возвраты. Я начинаю с короткого технического паспорта задачи.
Пример промпта:
Составь SQL-запрос для PostgreSQL.
Задача: посчитать выручку по неделям за последние 12 полных недель.
Таблицы:
orders(id, user_id, created_at, status)
payments(id, order_id, paid_at, amount, currency, status)
refunds(id, payment_id, refunded_at, amount)
Правила:
1. Учитывать только payments.status = 'paid'.
2. Учитывать только orders.status IN ('completed', 'shipped').
3. Выручка = сумма оплат минус сумма возвратов.
4. Неделя начинается в понедельник.
5. Текущую неполную неделю исключить.
Верни:
1. SQL.
2. Краткое объяснение логики.
3. Список возможных ошибок в данных.
В таком описании есть 3 защитных элемента: диалект базы, список колонок, правила расчёта. Если убрать хотя бы один, модель начнёт додумывать. Для MySQL, PostgreSQL, ClickHouse и аналитических хранилищ функции дат отличаются, и это частая причина поломок. Например, date_trunc('week', paid_at) нормально читается в PostgreSQL, но не переносится в любой движок без изменений.
Если задача относится к регулярному контенту, отчётам или маркетинговой аналитике, можно связать подход с общей практикой применения ИИ в рабочих процессах. Я подробно разбирал это в статье про внедрение нейросетей в рабочие процессы: там логика та же, сначала сценарий, потом шаблон, потом контроль качества.
Шаг 2. Получите первый SQL, но не считайте его готовым
Нейросеть может вернуть такой черновик:
WITH paid_orders AS (
SELECT
p.id AS payment_id,
p.paid_at,
p.amount AS paid_amount,
COALESCE(SUM(r.amount), 0) AS refunded_amount
FROM payments p
JOIN orders o ON o.id = p.order_id
LEFT JOIN refunds r ON r.payment_id = p.id
WHERE p.status = 'paid'
AND o.status IN ('completed', 'shipped')
AND p.paid_at >= date_trunc('week', CURRENT_DATE) - INTERVAL '12 weeks'
AND p.paid_at < date_trunc('week', CURRENT_DATE)
GROUP BY p.id, p.paid_at, p.amount
)
SELECT
date_trunc('week', paid_at)::date AS week_start,
SUM(paid_amount - refunded_amount) AS net_revenue
FROM paid_orders
GROUP BY week_start
ORDER BY week_start;
Черновик выглядит аккуратно. Но я сразу проверяю 5 мест.
- Возвраты суммируются по платежу, значит один платёж с двумя возвратами не задвоит оплату.
- Фильтр по дате стоит на
paid_at, а не наcreated_atзаказа. - Текущая неделя исключена через верхнюю границу.
- Валюта не обработана. Если в таблице есть несколько валют, запрос нельзя принимать без конвертации или группировки.
- Часовой пояс не задан. Для отчёта по московскому времени это может сдвинуть платежи около полуночи.
Пятый пункт часто кажется мелким, пока отчёт не расходится на 1–2 процента с финансовой витриной. Для недельных агрегатов это заметно на границах периода: воскресенье 23:30 UTC и понедельник 02:30 по локальному времени могут попасть в разные недели.
Шаг 3. Запустите ревью через отдельный промпт
Я не прошу ту же модель «проверь себя» в свободной форме. Лучше дать роль ревьюера и критерии. Так меньше шансов получить общую похвалу вместо проверки.
Проверь SQL как ревьюер данных.
Найди:
1. Синтаксические ошибки PostgreSQL.
2. Ошибки в бизнес-логике.
3. Риск дублей из-за JOIN.
4. Проблемы с NULL.
5. Проблемы с датами и часовыми поясами.
6. Что будет на данных с несколькими валютами.
Ответ верни таблицей: проблема, почему это риск, как исправить.
Хороший ответ должен быть конкретным. Например: «если refunds.amount может быть NULL, COALESCE внутри SUM не защищает от всех вариантов» или «currency есть в схеме, но не участвует в расчёте». Если модель пишет «запрос в целом корректен», я прошу её придумать 10 строк тестовых данных, на которых запрос даст неверный результат. Это резко меняет качество проверки.
Двухэтапная схема «генератор плюс ревьюер» особенно полезна, когда SQL сложнее 30–40 строк. Генератор собирает структуру. Ревьюер атакует её как тестировщик: ищет дубли, неверные границы и зависимость от пустых значений. В SoftChat для этого можно переключать модель в рамках разговора, когда нужен другой стиль ответа, при этом контекст диалога остаётся под рукой.
Шаг 4. Проверьте результат на малой выборке за 1 минуту
Самый быстрый тест SQL не требует полного запуска на боевой базе. Достаточно 5–10 строк, где заранее понятен ответ. Такой тест ловит больше ошибок, чем чтение запроса глазами.
Мини-набор данных:
orders
id | user_id | created_at | status
1 | 10 | 2026-05-04 10:00:00 | completed
2 | 11 | 2026-05-05 11:00:00 | shipped
3 | 12 | 2026-05-06 12:00:00 | cancelled
payments
id | order_id | paid_at | amount | currency | status
1 | 1 | 2026-05-05 09:00:00 | 1000 | RUB | paid
2 | 2 | 2026-05-06 09:00:00 | 2000 | RUB | paid
3 | 3 | 2026-05-07 09:00:00 | 3000 | RUB | paid
4 | 1 | 2026-05-08 09:00:00 | 500 | RUB | failed
refunds
id | payment_id | refunded_at | amount
1 | 2 | 2026-05-09 09:00:00 | 300
Ожидаемый результат для недели с 4 мая 2026 года: 2700 RUB. Платёж по отменённому заказу не входит. Неуспешная оплата не входит. Возврат 300 вычитается из оплаты 2000.
После этого я прошу модель составить тестовые сценарии:
На основе схемы и SQL составь 8 тестов.
Для каждого теста укажи входные строки, ожидаемый результат и ошибку, которую он ловит.
Не используй реальные персональные данные.
Обычно нужны тесты на 8 классов ошибок: пустые возвраты, два возврата на один платёж, несколько валют, отменённый заказ, платёж вне периода, платёж на границе недели, NULL в сумме, дубли в связующей таблице. Если запрос проходит эти случаи, он ещё не идеален, но уже не сырой.
Шаг 5. Оптимизируйте запрос после проверки логики
Оптимизация до проверки логики вредна. Можно ускорить неверный запрос и получить неправильные данные быстрее. Я сначала добиваюсь корректности, потом смотрю план выполнения.
Для PostgreSQL базовый цикл такой:
EXPLAIN ANALYZE
WITH paid_orders AS (
SELECT
p.id AS payment_id,
p.paid_at,
p.amount AS paid_amount,
COALESCE(SUM(r.amount), 0) AS refunded_amount
FROM payments p
JOIN orders o ON o.id = p.order_id
LEFT JOIN refunds r ON r.payment_id = p.id
WHERE p.status = 'paid'
AND o.status IN ('completed', 'shipped')
AND p.paid_at >= date_trunc('week', CURRENT_DATE) - INTERVAL '12 weeks'
AND p.paid_at < date_trunc('week', CURRENT_DATE)
GROUP BY p.id, p.paid_at, p.amount
)
SELECT
date_trunc('week', paid_at)::date AS week_start,
SUM(paid_amount - refunded_amount) AS net_revenue
FROM paid_orders
GROUP BY week_start
ORDER BY week_start;
Дальше я передаю план выполнения модели и прошу объяснить его простым языком. Нейросеть хорошо подсвечивает очевидные сигналы: последовательное чтение большой таблицы, дорогую сортировку, соединение без индекса, фильтр после соединения вместо раннего отбора.
Типовые варианты улучшения:
CREATE INDEX idx_payments_status_paid_at
ON payments (status, paid_at);
CREATE INDEX idx_orders_status_id
ON orders (status, id);
CREATE INDEX idx_refunds_payment_id
ON refunds (payment_id);
Но индекс не бесплатный. Он занимает место и замедляет вставку или обновление строк. Поэтому я прошу модель не просто «предложить индексы», а оценить, какие условия запроса их используют. Формулировка такая:
Проанализируй план выполнения и предложи только те индексы,
которые используются фильтрами или соединениями в этом запросе.
Для каждого индекса объясни, какую часть запроса он ускоряет
и какой у него возможный минус при записи данных.
Для аналитического запроса на витрине с ежедневным обновлением индекс может быть оправдан. Для таблицы событий с тысячами вставок в минуту решение надо проверять осторожнее. Нейросеть подсказывает гипотезу, а база подтверждает или опровергает её цифрами из плана.
Метрики качества SQL, которые я проверяю
В обновлённой версии я добавил отдельную таблицу метрик. Без неё разговор о «хорошем запросе» слишком расплывчатый.
| Метрика | Как проверить | Хороший признак | Красный флаг |
|---|---|---|---|
| Корректность | Сравнить с ручным расчётом на 5–10 строках | Ожидаемая сумма совпала | Расхождение на границе периода |
| Полнота логики | Сверить правила задачи с WHERE и JOIN | Все статусы и исключения учтены | В задаче есть возвраты, в SQL их нет |
| Устойчивость к NULL | Добавить строки с пустыми значениями | Результат не пропадает целиком | SUM возвращает NULL там, где нужен 0 |
| Защита от дублей | Проверить связи один-ко-многим | Оплата не умножается на число возвратов | JOIN увеличивает сумму |
| Производительность | Посмотреть EXPLAIN ANALYZE | Фильтры применяются рано | Полное чтение большой таблицы без причины |
| Читаемость | Дать запрос другому аналитику | CTE и имена понятны | 120 строк без структуры и комментариев |
Эти метрики можно превратить в шаблон ревью. Тогда каждый новый запрос проходит одинаковый фильтр, а качество меньше зависит от усталости аналитика. В статье про нейросети для генерации текста и проверки результата я разбирал похожую мысль на примере редакторских задач: модель полезнее, когда у неё есть критерии, а не просьба «сделай хорошо».
Ошибки, которые нейросеть пропускает чаще всего
Первая ошибка: выдуманные поля. Если в промпте нет схемы, модель легко добавит deleted_at, is_active или total_amount. Названия выглядят привычно, но в вашей базе их может не быть.
Вторая ошибка: неверный уровень агрегации. Например, отчёт нужен по заказам, а запрос агрегирует платежи. Если один заказ может иметь 2 оплаты, цифры съедут.
Третья ошибка: фильтр по неправильной дате. Заказ создан в апреле, оплачен в мае. Для выручки обычно нужен месяц оплаты, для операционного отчёта может быть нужна дата создания. Это нельзя угадывать.
Четвёртая ошибка: смешение валют. Если в таблице есть currency, модель обязана либо группировать по валюте, либо подключить курс, либо явно написать, что конвертации не хватает.
Пятая ошибка: оптимизация без статистики. Совет «добавить индекс» может быть верным на таблице в 50 миллионов строк и лишним на справочнике из 300 строк.
Как встроить этот процесс в работу команды
Я бы не начинал с подключения нейросети ко всем отчётам. Гораздо безопаснее выбрать 3–5 повторяемых SQL-задач: недельная выручка, активные пользователи, просроченные счета, конверсия из регистрации в оплату, сверка возвратов. Для каждой задачи нужен один шаблон постановки, один шаблон ревью и один минимальный набор тестовых данных.
Условный пример: команда аналитики из 4 человек договорилась проверять каждый новый запрос по 6 пунктам: схема, диалект, границы дат, дубли, NULL, план выполнения. Даже без точного замера экономии такой порядок снижает число возвратов на доработку, потому что спор идёт не о вкусе, а о конкретном пункте чек-листа.
SoftChat подходит для такого сценария как рабочий чат с историей, шаблонами промптов и выбором модели в рамках разговора. Если выбранная модель не возвращает пригодный ответ, в веб-чате и Telegram-боте предусмотрено получение ответа на резервной модели с понятным сообщением. Это полезно именно в длинных технических диалогах: не нужно заново собирать контекст из схемы, правил и промежуточных проверок.
Чек-лист перед запуском SQL в рабочем контуре
Перед тем как отдавать запрос в отчёт или автоматизацию, я прохожу короткий список.
- В запросе нет полей, которых нет в схеме.
- Диалект SQL совпадает с базой.
- Все бизнес-правила из задачи отражены в WHERE, JOIN или CTE.
- Границы дат заданы явно, текущий неполный период обработан отдельно.
- NULL не ломает суммы и счётчики.
- Связи один-ко-многим не умножают строки.
- Валюта, часовой пояс и статусы обработаны явно.
- Есть тест на 5–10 строк с ожидаемым результатом.
- План выполнения не показывает очевидно дорогую операцию без причины.
- Запрос можно объяснить коллеге за 2 минуты.
Последний пункт звучит мягко, но он практичный. Если автор не может быстро объяснить SQL, поддерживать его будет тяжело. Нейросеть может помочь написать комментарии к CTE и краткую документацию для отчёта, но смысл запроса всё равно должен оставаться понятным человеку.
Заключение: обновлённый подход к SQL с ИИ
После обновления я оставляю главный принцип таким: нейросеть ускоряет SQL, когда работает в паре с проверкой. Просить её сразу выдать «правильный запрос» рискованно. Надёжнее строить процесс из 5 шагов: точная постановка, черновик, ревью, тест на малой выборке, оптимизация по плану выполнения.
Модельный кейс с 4 часами ручной работы показывает не магию, а структуру экономии: часть времени уходит из набора кода, часть из поиска очевидных ошибок, часть из подготовки тестов. Финальное решение остаётся за специалистом, который знает данные, бизнес-правила и цену ошибки. Именно такой баланс я считаю рабочим для SQL в 2026 году.