Работа с внешними источниками данных (ВИД) в 1С — это мощный инструмент для интеграции, однако при взаимодействии с СУБД MySQL разработчики часто сталкиваются с неприятной особенностью платформы. Проблема проявляется при попытке записать данные в таблицу, где первичный ключ является строкой (тип VARCHAR), а не числом. Платформа 1С генерирует специфический SQL-запрос, который вызывает ошибку: [MySQL][ODBC Driver][mysqld] Truncated incorrect INTEGER value.
В этой статье мы подробно разберем, почему возникает эта ошибка, как проанализировать запросы, отправляемые платформой, и какой способ настройки внешнего источника является наиболее надежным для решения данной проблемы.
Давайте проанализируем ситуацию. Когда мы подключаем таблицу MySQL как объектную (то есть 1С воспринимает её как аналог справочника или документа), платформа пытается автоматически управлять идентификаторами. Даже если в настройках внешнего источника мы указали, что поле ключа — это строка, 1С при формировании запроса INSERT часто использует встроенную функцию MySQL LAST_INSERT_ID().
Рассмотрим реальный пример SQL-запроса, который уходит из 1С на сервер MySQL (как было выявлено в ходе обсуждения):
INSERT INTO cardTemp (idcard, idcardgroup, number, ...)
VALUES(LAST_INSERT_ID('0000AD52FFA3'), '1', 'B10000AD52FFA301', ...)
Здесь кроется главная проблема: функция LAST_INSERT_ID(expr) в MySQL предназначена для работы с целыми числами (типа BIGINT). Она принимает аргумент, устанавливает его как значение последнего вставленного ID и возвращает его. Но если передать в неё строку '0000AD52FFA3', MySQL пытается привести её к целому числу. Если строка не является числовой, СУБД в режиме строгого соответствия типов (Strict Mode) выдает ошибку Truncated incorrect INTEGER value.
Таким образом, мы видим «баг» или особенность реализации драйверов и транслятора запросов 1С: платформа ошибочно полагает, что первичный ключ в MySQL всегда должен проходить через механизм получения последнего ID, что справедливо для AUTO_INCREMENT, но ломает логику при использовании строковых кодов (например, GUID или артикулов).
Это самый эффективный и рекомендуемый способ решения. Когда таблица во внешнем источнике данных помечена как объектная, 1С навязывает ей поведение ссылочного типа. Если мы снимем флаг Объектная таблица в свойствах таблицы в конфигураторе, 1С начнет воспринимать её как набор записей (аналог регистра сведений).
Разберем по шагам, что нужно сделать:
idcard.Теперь, когда таблица стала «необъектной», 1С перестанет использовать LAST_INSERT_ID() при записи. Вместо этого будет генерироваться чистый INSERT INTO или UPDATE, где строковое значение будет передаваться как обычный литерал в кавычках.
После того как мы сделали таблицу необъектной, метод СоздатьОбъект() станет недоступен. Теперь для работы с данными мы должны использовать СоздатьМенеджерЗаписи() или СоздатьНаборЗаписей(). Рассмотрим, как правильно реализовать запись в этом случае.
Пример использования Менеджера записи:
Этот способ удобен, когда нужно работать с одной конкретной строкой таблицы. Мы устанавливаем ключ, пытаемся прочитать данные (чтобы 1С поняла, существует ли запись) и записываем изменения.
НоваяКарта = ВнешниеИсточникиДанных.Artix.Таблицы.cardTemp.СоздатьМенеджерЗаписи();
НоваяКарта.idcard = "0000AD530FA3"; // Наш строковый ключ
НоваяКарта.Прочитать(); // Пытаемся найти существующую запись
// Заполняем остальные реквизиты
НоваяКарта.idcardgroup = 1;
НоваяКарта.number = "B1" + НоваяКарта.idcard + "01";
НоваяКарта.cardstatus = 1;
// Записываем. Параметр Истина означает режим замещения (аналог REPLACE в SQL)
НоваяКарта.Записать(Истина);
Пример использования Набора записей:
Если нам нужно записать данные с предварительным отбором, лучше использовать НаборЗаписей. Это критически важно, чтобы 1С не пыталась очистить всю таблицу перед записью (что может случиться, если не установить отбор).
Набор = ВнешниеИсточникиДанных.Artix.Tables.cardTemp.СоздатьНаборЗаписей();
Набор.Отбор.idcard.Установить("0000AD530FA3");
Набор.Прочитать();
Если Набор.Количество() = 0 Тогда
НоваяСтрока = Набор.Добавить();
НоваяСтрока.idcard = "0000AD530FA3";
Иначе
НоваяСтрока = Набор[0];
КонецЕсли;
НоваяСтрока.idcardgroup = 1;
// ... заполнение других полей
Набор.Записать(Истина);
Важное замечание: При работе с необъектными таблицами через НаборЗаписей, 1С выполняет операцию DELETE по полям отбора перед INSERT. Убедитесь, что в свойствах таблицы во внешнем источнике ключевые поля (измерения) указаны верно, иначе вы рискуете случайно очистить лишние данные.
Если изменение структуры внешнего источника на «необъектную таблицу» по каким-то причинам не подходит, проанализируем смежные факторы:
my.ini (или my.cnf) найдите строку sql_mode и удалите оттуда упоминания STRICT. Это заставит MySQL вместо ошибки выдавать предупреждение (Warning) и продолжать выполнение запроса. Однако помните, что это может привести к неявному искажению данных в других частях системы.SET GLOBAL general_log = 'ON';.Подведем итог: использование строковых первичных ключей в объектных таблицах внешних источников 1С при работе с MySQL является проблемной зоной из-за некорректного использования функции LAST_INSERT_ID() платформой. Переход к необъектным таблицам с использованием Менеджера записи — это наиболее грамотное и «чистое» архитектурное решение, которое снимает проблему несовместимости типов и обеспечивает стабильную работу интеграции.