«You have an error in your SQL syntax»: разбор и фикс

SQL Автор: Среда и версия: MySQL 8 в чистом контейнере; точечная версия не зафиксирована

«You have an error in your SQL syntax» — это ошибка 1064, самая частая в MySQL. Она не говорит, что именно не так, только где парсер сдался. Дальше — как читать это сообщение, и пять причин, которые дают его чаще всего, каждая с реальным запросом, реальной ошибкой и рабочим исправлением. Проверено на MySQL 8 в чистом контейнере.

Как читать «near ’…’ at line N»

Вот минимальный пример. Таблица orders с полями id, customer, amount, status, опечатка в ключевом слове:

SELECT * FORM orders;
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to use
near 'FORM orders' at line 1

near 'FORM orders' — это не место опечатки, а хвост запроса, начиная с токена, на котором парсер застрял. MySQL разбирает SQL слева направо и ожидает после SELECT * ключевое слово FROM. Встретив FORM, он не может продолжить разбор и печатает всё, что осталось непрочитанным. Сама опечатка почти всегда лежит в начале этого хвоста или прямо перед ним, здесь это первое слово, FORM.

Правило, которое экономит время на длинных запросах: не ищи ошибку в указанном месте, ищи её сразу перед ним. Проверим на многострочном запросе:

SELECT id, customer, amount
FROM orders
WHER status = 'paid';
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to use
near 'status = 'paid'' at line 3

at line 3 — это реальная строка, парсер её не путает. А вот near 'status = 'paid'' не включает саму опечатку WHER: слово WHER парсер не узнал вообще, счёл началом нового, нераспознанного выражения, и хвост печатает с того места, где попытка разбора провалилась окончательно, с status. Опечатка на строку выше конца хвоста, а не внутри него. Если сообщение указывает на середину строки, а видимой ошибки там нет, посмотри на слово прямо перед этим местом: почти всегда там либо опечатка в ключевом слове, либо незакрытая конструкция.

Причина 1: зарезервированное слово без бэктиков

order, group, key, rank — обычные английские слова, и их тянет использовать как имена колонок. Для парсера это ключевые слова языка.

CREATE TABLE test_order (id INT, order INT);
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to use
near 'order INT)' at line 1

Парсер дошёл до order и ожидал что угодно, кроме ключевого слова ORDER в позиции, где нужно имя колонки. Фикс — бэктики, они говорят «дальше идёт идентификатор, а не ключевое слово»:

CREATE TABLE test_order (id INT, `order` INT);
INSERT INTO test_order VALUES (1, 5);
SELECT * FROM test_order;
id	order
1	5

Работает и с group, и с key, и с rank. Общий совет для новых схем: не называть колонки зарезервированными словами вообще, даже если бэктики решают проблему сейчас. Они понадобятся в каждом запросе к этой таблице.

Причина 2: лишняя или пропущенная запятая

Лишняя запятая перед FROM: частый результат правки списка колонок, когда последнюю удалили, а запятую перед ней забыли.

SELECT id, customer, FROM orders;
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to use
near 'FROM orders' at line 1

Фикс — убрать висящую запятую:

SELECT id, customer FROM orders;
id	customer
1	Аня
2	Борис
3	Глеб

С пропущенной запятой хуже: между двумя простыми именами колонок MySQL не всегда ругается, а молча трактует второе как алиас первого. SELECT id, customer amount FROM orders не упадёт, а вернёт колонку amount с данными из customer, подписанную как amount. Ошибку без обмана даёт только полное отсутствие разделителей между тремя и более идентификаторами:

SELECT id customer amount FROM orders;
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to use
near 'amount FROM orders' at line 1
SELECT id, customer, amount FROM orders;
id	customer	amount
1	Аня	900
2	Борис	1200
3	Глеб	500

Тот же паттерн ловит запятую в VALUES:

INSERT INTO orders VALUES (4 'Вера' 300 'paid');
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to use
near ''Вера' 300 'paid')' at line 1
INSERT INTO orders VALUES (4, 'Вера', 300, 'paid');
id	customer	amount	status
4	Вера	300	paid

Вывод из этих двух случаев: если запрос упал, ищи опечатку по хвосту сообщения. Если не упал, но вернул не то, что ожидалось, первый подозреваемый тоже запятая — просто пропущенная там, где соседние слова случайно образовали валидный алиас.

Причина 3: кавычки

Незакрытая строка: MySQL считает кавычкой всё до конца запроса или до следующей одиночной кавычки, поэтому сообщение об ошибке само содержит хвост исходного текста внутри кавычек:

SELECT * FROM orders WHERE customer = 'Аня;
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to use
near ''Аня' at line 1
SELECT * FROM orders WHERE customer = 'Аня';
id	customer	amount	status
1	Аня	900	paid

Второй вариант хуже диагностируется: «умные» кавычки “ ”, которые редактор Word или мессенджер подставляют вместо прямых при автозамене. Визуально в тексте всё выглядит нормально:

SELECT * FROM orders WHERE customer = “Аня”;
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to use near
'<0x80><0x9c>Аня<0xe2><0x80>' at line 1

Хвост сообщения превращается в нечитаемые байты (в терминале это либо , либо пустые квадраты — зависит от шрифта). Дело не в кодировке терминала: и в UTF-8 занимают три байта каждая, а MySQL вырезает хвост как окно байтов вокруг места ошибки, не заботясь о границах символа. Отсюда обрубленные с двух сторон куски кавычек в самом сообщении. Если вместо текста запроса в ошибке вопросительные знаки или кракозябры, почти наверняка это скопированные откуда-то не прямые кавычки. Лечится заменой на ':

SELECT * FROM orders WHERE customer = 'Аня';

Работает, как показано выше.

Причина 4: порядок предложений

SQL проверяет порядок предложений строго: SELECT … FROM … WHERE … GROUP BY … HAVING … ORDER BY … LIMIT. Переставить WHERE после GROUP BY — рабочая опечатка, потому что по смыслу «сначала группировка, потом фильтр» иногда кажется логичнее:

SELECT status, count(*) FROM orders GROUP BY status WHERE status = 'paid';
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to use
near 'WHERE status = 'paid'' at line 1
SELECT status, count(*) FROM orders WHERE status = 'paid' GROUP BY status;
status	count(*)
paid	3

Причина в том, что WHERE фильтрует строки до группировки, поэтому синтаксически он обязан стоять раньше GROUP BY. Подробнее о том, что каждое из этих предложений делает и почему HAVING, а не WHERE, фильтрует уже посчитанные группы, в статье про GROUP BY.

Та же логика ловит LIMIT не в конце:

SELECT status, count(*) FROM orders LIMIT 10 GROUP BY status;
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to use
near 'GROUP BY status' at line 1
SELECT status, count(*) FROM orders GROUP BY status LIMIT 10;
status	count(*)
paid	3
cancelled	1

Причина 5: LIMIT внутри IN-подзапроса

Эта конструкция падает на MySQL 8 и сегодня, спустя годы после многих других снятых ограничений:

SELECT * FROM orders
WHERE id IN (SELECT id FROM orders ORDER BY amount DESC LIMIT 2);
ERROR 1235 (42000) at line 1: This version of MySQL doesn't yet support 'LIMIT &
IN/ALL/ANY/SOME subquery'

Код ошибки другой, 1235, а не 1064, и текст честно говорит «пока не поддерживается», а не «синтаксическая ошибка». Но ищут это сообщение по тому же запросу «error in my sql syntax», потому что для человека, который просто хотел топ-2 заказа внутри IN, разница не очевидна. Обход простой: вынести подзапрос в JOIN.

SELECT o.*
FROM orders o
JOIN (SELECT id FROM orders ORDER BY amount DESC LIMIT 2) top
  ON top.id = o.id
ORDER BY o.amount DESC;
id	customer	amount	status
2	Борис	1200	paid
1	Аня	900	paid

Подзапрос в FROM ограничений на LIMIT не имеет, только IN/ALL/ANY/SOME его отвергают. ORDER BY во внешнем запросе здесь не косметика: сам JOIN порядок строк не гарантирует, без него результат может прийти в любой последовательности. Про этот же приём, соединение с производной таблицей вместо подзапроса, подробнее в статье про JOIN.

Тот же класс ошибок в PostgreSQL

Справочник использует PostgreSQL в остальных статьях. Если ты пришёл сюда с MySQL, а дальше собираешься на Koddo решать задачи, они на PostgreSQL, и сообщение об ошибке выглядит иначе. Тот же запрос из причины 2, три идентификатора без запятых:

SELECT id customer amount FROM orders;
ERROR:  syntax error at or near "amount"
LINE 1: SELECT id customer amount FROM orders;
                           ^

Формат другой: syntax error at or near "…" вместо You have an error in your SQL syntax. Вместо хвоста PostgreSQL показывает саму строку запроса со стрелкой ^ под проблемным токеном. Стрелка полезнее хвоста: она указывает прямо на место, а не на «всё, что после». Логика чтения та же. Токен под стрелкой обычно не сама опечатка, а первое место, где парсер перестал понимать запрос, поэтому проверка «на слово раньше» работает и здесь.

Частые вопросы

Почему MySQL не говорит, какое именно слово неверно

Парсер SQL не проверяет орфографию, он разбирает грамматику. Он умеет сказать «дальше я не могу продолжить по правилам грамматики», но не умеет угадать, что имелось в виду. Отсюда и хвост вместо точного указания: это последняя точка, где разбор ещё шёл по правилам.

Что делать, если ошибка в очень длинном запросе и хвост бесполезен

Закомментировать запрос до последнего рабочего предложения и добавлять по одному. Ошибка 1064 всегда указывает на первое место, где парсер сломался: если урезанный до SELECT … FROM … вариант отрабатывает, а после добавления WHERE падает, проблема ровно в добавленной части.

Может ли ошибка синтаксиса быть на самом деле ошибкой прав доступа

Нет, у прав доступа своя ошибка. Пользователю без прав на INSERT MySQL отвечает ERROR 1142 (42000) at line 1: INSERT command denied to user '...'@'...' for table '...'. Код и текст другие: про таблицу и право, а не про грамматику. 1064 гарантированно про синтаксис запроса, не про то, что база отказалась его выполнять.

Где потренироваться писать запросы без таких ошибок

В пути «SQL для аналитиков» на Koddo задачи проверяются автоматически, и сообщение парсера — первое, что видишь при опечатке, ещё до перехода к логике запроса. Набор готовых задач с разборами — в задачах по SQL.

Источники