Как исправить ошибку внешней базы данных «Неправильный синтаксис около конструкции "<"» при записи данных?

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

При программной записи во внешние источники данных (ВИД) разработчики 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 не может разобрать и выдает синтаксическую ошибку на открывающем символе <.

К аналогичной ситуации могут приводить и другие факторы:

  1. Несовпадение типов данных: несоответствие строгих типов СУБД (например, datetime2, бинарные данные, uniqueidentifier, специфические строковые форматы) типам, настроенным в дереве метаданных 1С.
  2. Поля со свойством автоинкремента (IDENTITY): колонка в СУБД генерируется автоматически, но в метаданных 1С не настроена должным образом, из-за чего платформа пытается передать туда значение принудительно.
  3. Игнорирование ограничений DEFAULT в СУБД: значения по умолчанию, заданные на стороне SQL-сервера, не подставляются, поскольку 1С перечисляет все поля таблицы явно в секции VALUES(...).

Способы решения проблемы

Рассмотрим подробнее варианты исправления ошибки, начиная от быстрого программного решения и заканчивая правильной настройкой метаданных.

1. Явная инициализация всех обязательных полей в коде

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


Стр = ВнешниеИсточникиДанных.BDSQL.Таблицы.dbo_ML.СоздатьМенеджерЗаписи();
Стр.lineID = 1;
Стр.uid = Новый УникальныйИдентификатор();
Стр.Kontr = "000000001"; // Явно заполняем строковое или числовое поле

Стр.Записать();

Если точные значения еще не известны, инициализируем поля значениями по умолчанию для их типа: пустой строкой "", числом 0, датой Дата(1, 1, 1) или булевым Ложь.

2. Корректировка состава полей и свойств в конфигураторе

Чтобы исключить зависимость от обязательного заполнения всех колонок в коде, разберем настройки метаданных внешнего источника:

  1. Установка свойства «Разрешить Null»: откроем свойства таблицы внешнего источника в конфигураторе. Для колонок, которые могут не заполняться при записи, установим флаг Разрешить Null. В этом случае платформа сможет передавать в СУБД значение NULL вместо сбоя сериализации.
  2. Удаление лишних полей: если для решения прикладной задачи требуются только 2–3 колонки таблицы, а остальные служебные или заполняются триггерами СУБД, удалим неиспользуемые поля из состава таблицы внешнего источника в конфигураторе 1С. Менеджер записи перестанет включать их в запрос INSERT.

3. Проверка параметров соединения и типа СУБД

При динамическом подключении к внешнему источнику через код важно явно указывать тип целевой СУБД в объекте ПараметрыСоединенияВнешнегоИсточникаДанных, так как параметр из строки подключения может игнорироваться генератором запросов платформы:


Соед = Новый ПараметрыСоединенияВнешнегоИсточникаДанных;
Соед.СтрокаСоединения = "Driver={SQL Server};Server=SRV-SQL;Database=ExternalDB;Uid=sa;Pwd=secret;";
Соед.СУБД = "MSSQLServer"; // Указываем тип СУБД явно

Источник = ВнешниеИсточникиДанных.BDSQL;
Источник.УстановитьПараметрыСоединенияСеанса(Соед);

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

Если схема внешней таблицы сложная, содержит вычисляемые поля, внешние ключи или строгие ограничения целостности, работа через стандартный менеджер записи 1С может быть ограничена (отсутствие частичной вставки, отсутствие поддержки транзакций 1С для внешних источников). В таких случаях применяются альтернативные архитектурные решения:

  1. Хранимые процедуры и функции внешнего источника: в дереве метаданных 1С в ветке ВИД можно объявить функции, вызывающие хранимые процедуры внешней базы данных с передачей параметров. Вся логика валидации и формирования INSERT выполняется на стороне SQL Server.
  2. Прямое выполнение запросов через ADO: формирование параметризованных запросов через объект COMОбъект("ADODB.Command") позволяет точечно управлять перечнем обновляемых полей и типами данных без ограничений объектной модели ВИД.
← На главную