При программной записи во внешние источники данных (ВИД) разработчики 1С нередко сталкиваются с ошибкой СУБД: «Ошибка при выполнении запроса: Ошибка ODBC. SQLSTATE: 42000. Номер ошибки: 102. Описание: [Microsoft][ODBC SQL Server Driver][SQL Server]Неправильный синтаксис около конструкции "<"».
Разберем природу возникновения этой ошибки, выясним, откуда в тексте SQL-запроса появляется символ <, и рассмотрим пошаговые методы устранения неполадки.
Проанализируем ситуацию: в программном коде 1С мы создаем менеджер записи внешней таблицы, заполняем несколько реквизитов и вызываем метод Записать():
Стр = ВнешниеИсточникиДанных.BDSQL.Таблицы.dbo_ML.СоздатьМенеджерЗаписи();
Стр.lineID = 1;
Стр.uid = Новый УникальныйИдентификатор();
Попытка
Стр.Записать();
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;
В тексте модуля 1С никаких символов < нет. Однако при обращении к профайлеру СУБД (например, SQL Server Profiler) мы увидим, что платформа 1С генерирует следующий SQL-запрос:
INSERT INTO dbo_ML (Kontr, lineID, uid)
VALUES (<Bad type>, 1, N'848e1289-33e7-49d5-999b-ac0e2be57e0d')
Причина сбоя заключается в маркере <Bad type>. Платформа 1С при вызове метода Записать() включает в команду INSERT все поля таблицы, добавленные в состав внешнего источника данных в конфигураторе. Если поле в метаданных не имеет признака допустимости пустых значений, а в коде ему не присвоено значение нужного типа (оно остается со значением Неопределено), сериализатор платформы не может сформировать корректный SQL-литерал. Вместо значения подставляется служебный текст <Bad type>, который сервер SQL не может разобрать и выдает синтаксическую ошибку на открывающем символе <.
К аналогичной ситуации могут приводить и другие факторы:
datetime2, бинарные данные, uniqueidentifier, специфические строковые форматы) типам, настроенным в дереве метаданных 1С.VALUES(...).Рассмотрим подробнее варианты исправления ошибки, начиная от быстрого программного решения и заканчивая правильной настройкой метаданных.
Самый быстрый способ — убедиться, что всем полям менеджера записи присвоены корректные значения базовых типов. Проанализируем состав колонок таблицы и добавим недостающие поля:
Стр = ВнешниеИсточникиДанных.BDSQL.Таблицы.dbo_ML.СоздатьМенеджерЗаписи();
Стр.lineID = 1;
Стр.uid = Новый УникальныйИдентификатор();
Стр.Kontr = "000000001"; // Явно заполняем строковое или числовое поле
Стр.Записать();
Если точные значения еще не известны, инициализируем поля значениями по умолчанию для их типа: пустой строкой "", числом 0, датой Дата(1, 1, 1) или булевым Ложь.
Чтобы исключить зависимость от обязательного заполнения всех колонок в коде, разберем настройки метаданных внешнего источника:
NULL вместо сбоя сериализации.INSERT.При динамическом подключении к внешнему источнику через код важно явно указывать тип целевой СУБД в объекте ПараметрыСоединенияВнешнегоИсточникаДанных, так как параметр из строки подключения может игнорироваться генератором запросов платформы:
Соед = Новый ПараметрыСоединенияВнешнегоИсточникаДанных;
Соед.СтрокаСоединения = "Driver={SQL Server};Server=SRV-SQL;Database=ExternalDB;Uid=sa;Pwd=secret;";
Соед.СУБД = "MSSQLServer"; // Указываем тип СУБД явно
Источник = ВнешниеИсточникиДанных.BDSQL;
Источник.УстановитьПараметрыСоединенияСеанса(Соед);
Если схема внешней таблицы сложная, содержит вычисляемые поля, внешние ключи или строгие ограничения целостности, работа через стандартный менеджер записи 1С может быть ограничена (отсутствие частичной вставки, отсутствие поддержки транзакций 1С для внешних источников). В таких случаях применяются альтернативные архитектурные решения:
INSERT выполняется на стороне SQL Server.COMОбъект("ADODB.Command") позволяет точечно управлять перечнем обновляемых полей и типами данных без ограничений объектной модели ВИД.