Почему при выполнении составного SQL-запроса к MySQL через ADO в 1С возникает ошибка синтаксиса?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей IT и автоматизация бизнеса
← На главную

При разработке интеграций между 1С и внешними интернет-магазинами (например, OpenCart) программисты часто обращаются к базе данных MySQL напрямую через технологию COM-соединения ADODB.Connection и системный ODBC-драйвер. Нередко возникает ситуация, когда простые запросы на чтение данных отрабатывают корректно, однако при попытке выполнить пакет из нескольких команд (содержащий установку переменных сессии, транзакции и несколько операторов INSERT или UPDATE) платформа выдает ошибку:

[MySQL][ODBC Driver][mysqld] 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...

При этом тот же самый SQL-скрипт без ошибок выполняется в консоли phpMyAdmin. Разберем детально причины такого поведения и рассмотрим надежные способы решения этой задачи.

Причины возникновения ошибки

Проанализируем техническую сторону взаимодействия 1С, драйвера ODBC и СУБД MySQL:

  1. Запрет пакетных запросов (Multiple Statements) по умолчанию: Драйвер MySQL Connector/ODBC из соображений безопасности (в первую очередь для защиты от атак типа SQL Injection) по умолчанию блокирует передачу нескольких SQL-команд, разделенных точкой с запятой, в рамках одного вызова метода Execute. СУБД успешно считывает первую инструкцию (например, SET SQL_MODE = ...;), а последующий текст начинает интерпретировать как некорректное продолжение первой команды, что и вызывает синтаксическую ошибку.
  2. Специфика phpMyAdmin: Веб-интерфейсы и специализированные консоли администрирования перед отправкой запроса на сервер либо самостоятельно парсят скрипт на отдельные команды, либо открывают соединение со специальными клиентскими флагами, разрешающими пакетные операции.
  3. Несоответствие разрядности драйвера: Напомним важный нюанс: разрядность драйвера MySQL ODBC должна строго совпадать с разрядностью процесса 1С, выполняющего код. Для 32-битного клиента требуется 32-разрядный ODBC-драйвер, а для 64-битного сервера 1С — 64-разрядный.

Способ 1. Разделение запросов и управление транзакциями средствами ADO (Рекомендуемый)

Наиболее надежный и правильный подход при работе с базой через COM-объект — отказаться от склеивания команд в одну большую строку. Вместо явной передачи команд START TRANSACTION, COMMIT или ROLLBACK в тексте SQL-запроса следует использовать встроенные методы объекта ADODB.Connection.

Рассмотрим пример правильной организации пакетной записи данных в 1С:


Соединение = Новый COMОбъект("ADODB.Connection");
Соединение.ConnectionString = "DRIVER={MySQL ODBC 5.3 Unicode Driver};SERVER=localhost;DATABASE=shop_db;UID=root;PWD=password;OPTION=3;";
Соединение.Open();

// Открываем транзакцию средствами ADO
Соединение.BeginTrans();

Попытка
    // Выполняем установку параметров сессии отдельной командой
    Соединение.Execute("SET SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO'");
    Соединение.Execute("SET time_zone = '+00:00'");

    // Выполняем первую вставку данных
    ТекстЗапросаКатегории = 
        "INSERT INTO `do_category` (`category_id`, `image`, `parent_id`, `top`, `column`, `sort_order`, `status`, `date_added`, `date_modified`) " +
        "VALUES (2, 'catalog/Tovar/Samokat2.jpg', 0, 0, 1, 0, 1, '2023-01-01 00:00:00', '2023-01-01 00:00:00') " +
        "ON DUPLICATE KEY UPDATE `image` = VALUES(`image`), `parent_id` = VALUES(`parent_id`)";
    Соединение.Execute(ТекстЗапросаКатегории);

    // Выполняем вторую вставку данных
    ТекстЗапросаОписания = 
        "INSERT INTO `do_category_description` (`category_id`, `language_id`, `name`, `description`, `meta_title`, `meta_description`, `meta_keyword`) " +
        "VALUES (2, 1, 'Конструкторы', '', 'Конструкторы', 'Конструкторы', 'Конструкторы') " +
        "ON DUPLICATE KEY UPDATE `name` = VALUES(`name`), `description` = VALUES(`description`)";
    Соединение.Execute(ТекстЗапросаОписания);

    // Фиксируем транзакцию, если все команды завершились успешно
    Соединение.CommitTrans();
    
Исключение
    // В случае ошибки отменяем все изменения
    Соединение.RollbackTrans();
    Соединение.Close();
    ВызватьИсключение "Ошибка при записи данных в MySQL: " + ОписаниеОшибки();
КонецПопытки;

Соединение.Close();

Такой подход гарантирует атомарность всей пачки данных: если хотя бы один из запросов завершится ошибкой, метод RollbackTrans() откатит состояние таблиц к исходному.

Способ 2. Разрешение пакетных запросов в строке подключения ODBC

Если специфика алгоритма требует отправки готового монолитного SQL-скрипта (дампа), можно принудительно включить поддержку пакетных выражений на уровне драйвера. Для этого в строку подключения добавляется специальный флаг:

Добавьте в строку подключения параметр CLIENT_MULTI_STATEMENTS=1 или числовой флаг FLAG_MULTI_STATEMENTS в параметре OPTION (комбинация битовых флагов OPTION=67108864).


Соединение = Новый COMОбъект("ADODB.Connection");
СтрокаПодключения = "DRIVER={MySQL ODBC 5.3 Unicode Driver};SERVER=localhost;DATABASE=shop_db;UID=root;PWD=password;CLIENT_MULTI_STATEMENTS=1;";
Соединение.Open(СтрокаПодключения);
Соединение.Execute(ТекстСоставногоЗапроса);
Соединение.Close();

Обратите внимание: этот вариант снижает уровень защищенности базы данных и требует явной поддержки флага со стороны версии сервера MySQL.

Способ 3. Передача данных через веб-сервис / HTTP-интерфейс

Прямое подключение к СУБД сайта через внешнюю сеть (порт 3306) несет риски безопасности и часто блокируется хостинг-провайдерами. Альтернативный вариант — взаимодействие через HTTP-запросы.

Посмотрим на пример отправки данных из 1С на серверный скрипт:


HTTPСоединение = Новый HTTPСоединение("mysite.ru", 443, , , , 30, Новый ЗащищенноеСоединениеOpenSSL());
HTTPЗапрос = Новый HTTPЗапрос("/api/sync_categories.php");
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
HTTPЗапрос.Заголовки.Вставить("Authorization", "Bearer СекретныйТокенАвторизации");

// Формируем тело запроса (например, в формате JSON)
ТекстJSON = "{""category_id"": 2, ""name"": ""Конструкторы"", ""parent_id"": 0}";
HTTPЗапрос.УстановитьТелоИзСтроки(ТекстJSON, КодировкаТекста.UTF8);

Ответ = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Если Ответ.КодСостояния <> 200 Тогда
    ВызватьИсключение "Ошибка отправки данных: " + Ответ.ПолучитьТелоКакСтроку();
КонецЕсли;

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

Альтернативные штатные возможности платформы 1С

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

  1. Внешние источники данных: Механизм платформы 1С позволяет подключить внешнюю базу MySQL через системный DSN. Таблицы сторонней базы отображаются в дереве метаданных 1С, и разработчик может работать с ними с помощью стандартного языка запросов 1С и объектной модели (чтение, добавление, изменение записей) без ручного составления сложных SQL-команд.
  2. Штатный протокол обмена CommerceML: Для большинства интернет-магазинов (включая OpenCart) существуют готовые интеграционные модули, принимающие данные по типовому протоколу обмена 1С через формат XML/CommerceML, что избавляет от необходимости писать низкоуровневые SQL-запросы.
← На главную