Нейросеть для SQL: как писать запросы с ИИ и проверять их
Как писать SQL с нейросетью: что дать модели на вход, какие ошибки она делает и как их поймать. На примерах из эксперимента с 14 запросами к базе авиаперевозок.
Содержание статьи
Аналитик просит нейросеть посчитать средний чек бронирований, в которых есть хотя бы один билет бизнес-класса. Через секунду готов аккуратный запрос: три таблицы, JOIN, фильтр, AVG. Запрос выполняется без ошибок и возвращает 141 063 ₽. Верный ответ — 125 745 ₽: модель соединила бронирования с перелётами, строки задвоились, и дорогие бронирования попали в среднее по нескольку раз. Запрос из реального прогона, который мы провели на учебной базе. Нейросеть пишет SQL хорошо — заметно лучше, чем считает цифры в тексте. Но её запрос — черновик, и эта статья о том, как превратить черновик в результат.
Что нейросеть делает с SQL хорошо, а что — нет
Мы дали четырём моделям OpenAI схему базы авиаперевозок и 14 задач — от «сколько аэропортов в Москве» до «сколько пассажиров летали в августе и не летали в июле». Каждый запрос выполнили и сравнили результат с эталоном, каждую задачу — трижды. Лучшая модель решила все задачи, остальные — от 81 до 98% запросов. Простые запросы с одной таблицей и понятной группировкой не ломались ни разу.
Ошибки собрались в три узнаваемые группы, и все три видны глазом, если знать, куда смотреть.
- JOIN, который размножает строки, — и раздувает суммы и средние.
- Догадки о значениях в данных: «Moscow» вместо «Москва», статус не тем словом.
- Выдуманные столбцы и таблицы, которых нет в схеме.
Ошибка первая: JOIN, который размножает строки
Самая опасная ошибка, потому что запрос выполняется и возвращает правдоподобное число. В задаче про средний чек бронирование нужно было проверить на наличие бизнес-класса, а усреднять по самим бронированиям. Модель соединила таблицы подряд. У одного бронирования несколько билетов, у билета — несколько перелётов, и одно бронирование превратилось в несколько строк. Вместо 83 730 бронирований в среднее попали 107 642 строки, и больше всего повторов было у крупных бронирований на семью — поэтому среднее выросло.
SELECT ROUND(AVG(b.total_amount)) AS avg_total
FROM bookings b
JOIN tickets t ON b.book_ref = t.book_ref
JOIN ticket_flights tf ON t.ticket_no = tf.ticket_no
WHERE tf.fare_conditions = 'Business';Как это починить и как заметить
Условие «есть хотя бы один» пишется через EXISTS: тогда каждое бронирование проверяется, но не размножается. Заметить ошибку помогает одна привычка — считать строки до и после соединения. Если вы усредняете бронирования, строк должно быть столько же, сколько бронирований.
SELECT ROUND(AVG(total_amount)) AS avg_total
FROM bookings b
WHERE EXISTS (
SELECT 1
FROM tickets t
JOIN ticket_flights tf USING (ticket_no)
WHERE t.book_ref = b.book_ref AND tf.fare_conditions = 'Business'
);В задаче про загрузку рейсов одна из моделей присоединила к рейсу сразу места в самолёте и посадочные талоны. Строки перемножились, и средняя загрузка вышла 68,5% вместо 35,1%. Правило то же: считайте каждую сущность в отдельном подзапросе и соединяйте уже готовые итоги.
Ошибка вторая: догадки о значениях
Одна из моделей во всех трёх прогонах искала вылеты из Москвы условием city = 'Moscow'. В базе города записаны по-русски, запрос вернул ноль перелётов вместо 7 419 — и ноль, в отличие от раздутого среднего, хотя бы бросается в глаза. Модель не виновата: в схеме, которую мы дали, не было сказано, на каком языке названия. Она угадала — и не угадала.
Лечится это контекстом. Кроме названий столбцов, дайте модели по несколько реальных значений для тех, по которым будет фильтр: города, статусы, типы. Их легко достать одним запросом.
SELECT DISTINCT city FROM airports ORDER BY city LIMIT 10;
SELECT status, count(*) FROM flights GROUP BY status;Ошибка третья: выдуманные столбцы
Иногда модель достраивает схему из общих представлений о том, «как обычно бывает». В одном прогоне модель соединила перелёты с местами по номеру места и взяла номер бронирования прямо из таблицы перелётов — ни того, ни другого столбца в ticket_flights нет. Такая ошибка безобидна в том смысле, что база сразу отвечает «столбец не найден». Но если похожий столбец случайно существует, запрос выполнится и вернёт не то.
Поэтому схему лучше давать целиком и дословно, а не пересказом. Проще всего выгрузить её из самой базы.
SELECT table_name, string_agg(column_name || ' ' || data_type, ', ' ORDER BY ordinal_position) AS columns
FROM information_schema.columns
WHERE table_schema = 'public'
GROUP BY table_name
ORDER BY table_name;Что давать нейросети на вход
Всё, что модель должна знать, помещается в полстраницы. Эти полстраницы стоит сохранить как шаблон и дополнять после каждой найденной ошибки.
СУБД: PostgreSQL 16.
Схема (из information_schema): <вставить>
Зерно: bookings — одно бронирование; tickets — билет пассажира (в бронировании бывает несколько);
ticket_flights — перелёт по билету на рейс (у билета бывает несколько перелётов).
Значения fare_conditions: 'Economy', 'Comfort', 'Business'.
Задача: средняя сумма бронирования среди бронирований, где есть хотя бы один перелёт бизнес-классом.
Ответ: одна колонка avg_total, округлить до рубля.
Проверь, что соединения не размножают бронирования. Верни только запрос.- СУБД и её версия: PostgreSQL, ClickHouse, DuckDB. Функции дат и строк в них разные.
- Схема: таблицы, столбцы, типы — дословно, из information_schema.
- Зерно каждой таблицы: что означает одна строка. «Одна строка ticket_flights — перелёт пассажира на рейс».
- Связи: какие столбцы соединяют таблицы и где связь «один ко многим».
- Примеры значений для столбцов, по которым фильтруете.
- Какой ответ нужен: названия колонок, одна строка на что, сортировка, округление.
- Ограничения: «не размножай строки при JOIN», «верни только запрос».
Как проверить запрос, который написала нейросеть
Проверка занимает пару минут и почти всегда находит ошибку, если она есть. Главное — не смотреть на результат как на ответ, пока не проверено, что запрос считает то, что нужно.
SELECT count(*) AS rows_after_join, count(DISTINCT b.book_ref) AS bookings
FROM bookings b
JOIN tickets t USING (book_ref)
JOIN ticket_flights tf USING (ticket_no)
WHERE tf.fare_conditions = 'Business';
-- 107 642 строки против 83 730 бронирований: среднее по таким строкам будет неверным- Прочитайте запрос сверху вниз и назовите зерно результата: одна строка — это что.
- После каждого JOIN посчитайте строки: count(*) и count(DISTINCT ключа) должны совпадать там, где сущность не должна размножаться.
- Сверьте итог с известной цифрой: общая выручка, число заказов, значение из вчерашнего отчёта.
- Посчитайте одну группу вручную простым фильтром и сравните.
- Проверьте краевые случаи: NULL, нули, границы дат, записи без пары при LEFT JOIN.
- Если результат — ноль или пусто, сначала проверьте условия фильтра: не угадала ли модель значение.
Рабочий цикл: от вопроса до проверенной цифры
Нейросеть ускоряет SQL только тогда, когда вокруг неё выстроен короткий повторяемый процесс. Без процесса аналитик тратит сэкономленные минуты на то, чтобы выяснять, откуда в отчёте взялась странная цифра.
Первый шаг делается один раз: соберите файл со схемой — выгрузку из information_schema, зерно каждой таблицы одной фразой, связи и примеры значений для столбцов-справочников. Этот файл и есть ваш основной промпт. Вопрос добавляется к нему в конце.
Второй шаг — формулировка вопроса в терминах результата: какие колонки, одна строка на что, за какой период, как округлять. «Выручка по городам за август» превращается в «колонки city и revenue, одна строка на город вылета, рейсы с плановым вылетом с 1 по 31 августа включительно». Половина ошибок в эксперименте исчезла бы, если бы условие было записано так же подробно.
Третий шаг — выполнить запрос на ограниченных данных, например за один день, и посмотреть на результат глазами: число строк, порядок величин, пустые значения. Четвёртый — сверка с известным итогом. Пятый — если нашлась ошибка, добавить в файл со схемой правило, которое её предотвратило бы. Через пару недель шаблон знает все ловушки ваших данных, и ошибок становится заметно меньше.
Как вернуть модели ошибку, чтобы она её исправила
Сообщение «неправильно, исправь» почти никогда не работает: модель переписывает запрос наугад и может сломать то, что было верным. Работает конкретная обратная связь — то, что вы увидели при проверке, числами.
Для раздутого среднего хватит одной фразы с результатом проверочного запроса: после соединений строк стало 107 642, а бронирований с бизнес-классом 83 730, значит, среднее считается по задвоенным строкам; перепиши так, чтобы каждое бронирование учитывалось один раз. Для нуля вместо результата — список реальных значений столбца. Для ошибки базы — её полный текст: сообщения вроде «column does not exist» модели исправляют хорошо, если видят их целиком.
Запрос выполнился, но результат неверный.
Проверка: после JOIN строк 107 642, уникальных book_ref — 83 730.
Значит, одно бронирование попадает в AVG несколько раз.
Перепиши запрос так, чтобы каждое бронирование учитывалось один раз
(например, через EXISTS), и объясни, что изменилось.Какие инструменты использовать
Для SQL подходят три вида инструментов, и выбор между ними — вопрос удобства и правил компании, а не качества модели.
Чат-бот общего назначения — самый гибкий вариант: вставляете схему и вопрос, получаете запрос, выполняете у себя. Данные в чат не уходят, только описание таблиц. Помощник в редакторе кода или в клиенте базы данных удобнее тем, что видит схему сам и подставляет запрос прямо в окно, где вы его выполните. Встроенные функции BI-систем, которые строят запрос по вопросу на естественном языке, хороши для простых вопросов бизнес-пользователей, но аналитику важно видеть сгенерированный запрос — иначе проверить его нельзя.
Какая модель внутри — важно, но меньше, чем кажется. В нашем эксперименте разница между лучшей и худшей моделью в SQL составила 19 процентных пунктов, а доля верных ответов у одной и той же модели при переходе от ответа текстом к запросу росла на 49–68 пунктов (задачи в двух частях разные, но порядок разницы показателен).
Другие задачи с SQL, где нейросеть полезна
Писать запрос по описанию — не единственный сценарий. Часто нейросеть полезнее как собеседник по уже написанному коду.
| Сценарий | Как попросить | На что смотреть |
|---|---|---|
| Объяснить чужой запрос | «Объясни построчно, что считает этот запрос и какое у результата зерно» | Сверьте объяснение с результатом на маленькой выборке |
| Найти ошибку | Запрос + текст ошибки базы + схема | Исправление не должно менять смысл запроса |
| Перевести между диалектами | «Перепиши с PostgreSQL на ClickHouse, сохрани результат» | Функции дат и деления целых чисел |
| Ускорить запрос | Запрос + план выполнения (EXPLAIN ANALYZE) | Результат до и после должен совпадать до строки |
| Разбить на шаги | «Перепиши через CTE, по шагу на смысловую часть» | Промежуточные CTE можно выполнить отдельно |
Частые вопросы
Что такое text‑to‑SQL? Так называют перевод вопроса на обычном языке в SQL-запрос. Этим занимаются и чат-боты, и специальные функции BI-систем. Качество зависит от того, насколько подробно модели описаны данные: без схемы и примеров значений даже сильная модель будет угадывать.
Безопасно ли отдавать нейросети схему базы? Схема обычно не содержит данных клиентов, но может раскрывать устройство продукта. Проверьте правила компании; если нужно, переименуйте служебные таблицы и оставьте только те, что нужны для задачи. Сами строки для написания запроса модели не нужны.
Какая нейросеть лучше пишет SQL? В нашем эксперименте GPT-5.5 решила все 42 задачи, GPT-5.4 mini ошиблась один раз, GPT-4.1 mini и GPT-4o — заметно чаще. Но даже лучшая модель не знает ваших данных, поэтому проверка нужна при любом выборе.
Можно ли не проверять простые запросы? Простые запросы к одной таблице модели в эксперименте не ломали ни разу. Ошибки начинаются с соединений, условий «хотя бы один» и «не было» и с фильтров по значениям, которые модель не видела. Если в запросе есть JOIN — проверяйте.
Зачем учить SQL, если его пишет нейросеть
Каждую ошибку из этой статьи можно было поймать, только понимая SQL: видеть зерно таблицы, знать, что делает JOIN со связью «один ко многим», отличать EXISTS от соединения. Нейросеть снимает с аналитика набор текста, но не чтение. А читать запрос и замечать в нём ловушку — навык, который тренируется на задачах с проверкой, а не на готовых ответах.
Если SQL пока даётся с трудом, начните с основ: SELECT, фильтры, агрегаты, JOIN. После этого запросы нейросети перестают быть чёрным ящиком.
Материалы по теме
Материалы по теме
SQL-запросы: 40 примеров для аналитика с результатами
Сорок SQL-запросов на одной учебной базе: SELECT и WHERE, COUNT и GROUP BY, JOIN, даты, оконные функции, DAU, retention и A/B-тест. У каждого запроса показан результат.

ИИ в работе аналитика: где нейросеть помогает, а где врёт
Как аналитику работать с нейросетями: какие задачи ИИ ускоряет, где выдумывает цифры, как ставить задачу и проверять ответ. С результатами нашего эксперимента.

Нейросеть для Excel: формулы, сводные таблицы и проверка
Нейросеть для Excel и Google Таблиц: формулы ВПР и СУММЕСЛИМН, сводные таблицы, Power Query. Какие инструменты есть в 2026 году, где ИИ ошибается и как проверить формулу.