При интеграции 1С со сторонними базами данных MySQL через COM-объект ADO или ODBC-провайдер разработчики часто сталкиваются с ситуацией, когда строка из нескольких инструкций INSERT, разделенных точкой с запятой, успешно отрабатывает в веб-интерфейсе phpMyAdmin, но при вызове метода Execute() из 1С завершается ошибкой синтаксиса:
Microsoft OLE DB Provider for ODBC Drivers: [MySQL][ODBC Driver] 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 'INSERT INTO...
Проанализируем причины такого поведения и разберем по шагам надежные способы передачи данных из 1С в MySQL.
Главная причина заключается в том, что драйвер MySQL Connector/ODBC по умолчанию запрещает выполнение составных пакетов команд (Multi-Statement / Batch execution) в рамках одного вызова из соображений безопасности (защита от внедрения вредоносного SQL-кода). Панели администрирования баз данных (такие как phpMyAdmin или DBeaver) либо предварительно разбивают текст скрипта на отдельные команды перед отправкой на сервер, либо изначально подключаются с активным флагом пакетных запросов.
Когда мы передаем в метод mySQL.Execute(Стр) строку, содержащую несколько операторов INSERT через ;, драйвер считает точку с запятой синтаксической ошибкой и прерывает выполнение на второй команде.
Вместо отправки множества отдельных команд INSERT INTO ... VALUES (...); INSERT INTO ... стандартный синтаксис MySQL позволяет вставить множество строк одним SQL-выражением через запятую. Этот способ является оптимальным: он не требует изменения настроек драйвера и работает значительно быстрее одиночных вставок.
Посмотрим на пример формирования такого запроса в цикле выборки 1С:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РемонтОборудования.Номер КАК Номер,
| РемонтОборудования.Дата КАК Дата,
| РемонтОборудования.Ссылка КАК Ссылка,
| РемонтОборудования.Неисправность КАК Неисправность,
| РемонтОборудования.Контрагент.ПолноеНаименование КАК ФИО
|ИЗ
| Документ.РемонтОборудования КАК РемонтОборудования
|ГДЕ
| РемонтОборудования.ИзмененияВыгруженыНаСайт = ЛОЖЬ";
Выборка = Запрос.Выполнить().Выбрать();
МассивСтрокЗначений = Новый Массив;
Пока Выборка.Следующий() Цикл
Гуид = Строка(Выборка.Ссылка.УникальныйИдентификатор());
НомерДок = СтрЗаменить(Выборка.Номер, """", "'");
// Форматируем дату в стандартный для MySQL формат YYYY-MM-DD HH:MM:SS
ДатаСтр = Формат(Выборка.Дата, "ДФ=""yyyy-MM-dd HH:mm:ss""");
Неисправность = СтрЗаменить(Выборка.Неисправность, """", "'");
ФИО = СтрЗаменить(Выборка.ФИО, """", "'");
СтрокаЗначений = "(""" + Гуид + """, """ + НомерДок + """, """ + ДатаСтр + """, """ + Неисправность + """, """ + ФИО + """)";
МассивСтрокЗначений.Добавить(СтрокаЗначений);
КонецЦикла;
Если МассивСтрокЗначений.Количество() > 0 Тогда
ТекстSQL = "INSERT INTO `repairs_statuses` (`id`, `number`, `date`, `fault`, `fio`) VALUES "
+ СтрСоединить(МассивСтрокЗначений, ", ");
mySQLConnection.Execute(ТекстSQL);
КонецЕсли;
Если записей немного или логика обработки требует фиксировать результат выполнения каждой отдельной операции, выполним отправку запроса для каждого документа индивидуально на каждой итерации цикла:
Пока Выборка.Следующий() Цикл
Гуид = Строка(Выборка.Ссылка.УникальныйИдентификатор());
НомерДок = СтрЗаменить(Выборка.Номер, """", "'");
ДатаСтр = Формат(Выборка.Дата, "ДФ=""yyyy-MM-dd HH:mm:ss""");
Неисправность = СтрЗаменить(Выборка.Неисправность, """", "'");
ФИО = СтрЗаменить(Выборка.ФИО, """", "'");
ТекстSQL = "INSERT INTO `repairs_statuses` (`id`, `number`, `date`, `fault`, `fio`) "
+ "VALUES (""" + Гуид + """, """ + НомерДок + """, """ + ДатаСтр + """, """ + Неисправность + """, """ + ФИО + """);";
mySQLConnection.Execute(ТекстSQL);
ОбработкаПрерыванияПользователя();
КонецЦикла;
Если необходимо передавать именно пачку разнородных запросов в одной строке, разрешим драйверу исполнение множественных выражений (Multi-Statements):
MULTI_STATEMENTS=1; или флаг опции OPTION=67108864; (соответствует битовой маске 0x04000000).ДД.ММ.ГГГГ ЧЧ:ММ:СС. MySQL ожидает дату по стандарту ГГГГ-ММ-ДД ЧЧ:ММ:СС. Обязательно форматируем даты через Формат(Значение, "ДФ=""yyyy-MM-dd HH:mm:ss""").C:\Windows\SysWOW64\odbcad32.exe.CHARSET=utf8mb4 или выполним команду SET NAMES utf8mb4 сразу после открытия соединения.