Как исправить ошибки выполнения прямых запросов с УложитьСписокОбъектов в 1С++

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При переходе на прямые запросы с использованием внешней компоненты 1С++ и класса ODBCRecordset разработчики периодически сталкиваются с синтаксическими ошибками СУБД MS SQL Server. Особенно остро проблемы проявляются при выгрузке списков отбора во временные таблицы и при работе с виртуальными таблицами регистров. Рассмотрим по шагам распространенные ошибки, выясним их причины и проанализируем правильные варианты построения запросов.

Ошибка синтаксиса near 'table' при вызове УложитьСписокОбъектов

Частая ошибка при попытке передать список объектов (например, список контрагентов или номенклатуры) во временную таблицу выглядит следующим образом:

Internal error: State 42000, native 156, message [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near the keyword 'table'.

Проанализируем типовую ошибочную строку кода:

RS.УложитьСписокОбъектов(спсКлиенты, "#Klienti", "Контрагенты");

Причина возникновения ошибки заключается в неправильной передаче второго аргумента. Метод УложитьСписокОбъектов (или PutObjectList) принимает три параметра:

  1. Объект — список значений, группа справочника или отдельный элемент, который требуется поместить во временную таблицу.
  2. ИмяТабл — строковая переменная, передаваемая по ссылке (выходной параметр). Компонента генерирует уникальное системное имя временной таблицы и записывает его в эту переменную. Передавать строковый литерал (константу вида "#Klienti") нельзя.
  3. ВидСпр — строковое наименование вида справочника для корректного раскрытия иерархии групп.

Разберем правильный вызов метода:


ВрТаблГрупп = "";
RS.УложитьСписокОбъектов(спсКлиенты, ВрТаблГрупп, "Контрагенты");

После вызова переменная ВрТаблГрупп будет содержать реальное сгенерированное имя временной таблицы в базе данных (например, #vt_1_12345), которое затем необходимо подставить в текст SQL-запроса.

Использование полученной временной таблицы в тексте запроса

После того как временная таблица сформирована компонентой, мы используем ее в основном запросе. Временная таблица содержит колонку Val, в которой хранятся идентификаторы объектов (9-символьные строки ID). Посмотрим на пример фильтрации документов:


ВрТаблГрупп = "";
RS.УложитьСписокОбъектов(ВыбКонтр, ВрТаблГрупп, "Контрагенты");

ТекстЗапроса = "
|SELECT 
|    Док.IDDoc as [Док $Документ.Счет],
|    $Док.Контрагент as [Контрагент $Справочник.Контрагенты]
|FROM
|    $Документ.Счет as Док
|WHERE
|    $Док.Контрагент IN (SELECT Val FROM " + ВрТаблГрупп + ")
|";
табЗапрос = RS.ВыполнитьИнструкцию(ТекстЗапроса);

Если в запросе используется явное соединение JOIN, важно корректно указывать псевдонимы (алиасы) таблиц для полей соединения во избежание неоднозначности и ошибок сопоставления. Рассмотрим подробнее:


|FROM $РегистрОстаткиОбороты.ВзаиморасчетыПокупателей(...) AS Рег
|INNER JOIN " + ВрТаблГрупп + " AS ФильтрКлиенты ON ФильтрКлиенты.Val = Рег.Контрагент

Ошибка native 137: Необходимо объявить скалярную переменную @_CP_

При передаче дат в виртуальные таблицы регистров разработчики часто сталкиваются с ошибкой:

Meta name parser error: это метаимя разрешить невозможно "$РегистрОстаткиОбороты.ИмяРегистра" State 42000, native 137, message [Microsoft][ODBC SQL Server Driver][SQL Server]Необходимо объявить скалярную переменную "@_CP_2".

Выясним причину этой проблемы. В синтаксисе метапарсера 1С++ суффикс тильды ~ (например, :ДатаКонца~) означает смещение границы периода на конец дня (23:59:59). Метапарсер автоматически генерирует для таких конструкций внутренние переменные контекста с префиксом @_CP_.

Если параметр устанавливается методом SetTextParam, происходит простая текстовая подстановка значения в текст команды до работы метапарсера, и внутренняя переменная DECLARE @_CP_... не формируется. Чтобы избежать сбоя, необходимо соблюдать следующие правила:

  1. Для типизированных параметров запроса (особенно дат с модификатором границы ~) используем строго метод УстПараметр (или SetParameter), а не SetTextParam.
  2. Проверяем соответствие имени параметра: RS.УстПараметр("ДатаКонца", Дата2); связывается в тексте как :ДатаКонца~.
  3. Если требуется текстовая вставка готовой даты, убираем тильду и передаем строку фиксированного формата YYYYMMDD через SetTextParam, рассчитывая конец дня вручную.

Ограничение точности чисел в MS SQL Server 7.0 (Ошибка native 2750)

При выполнении запросов к виртуальным таблицам итогов на старых версиях СУБД (MS SQL Server 7.0) может возникать ошибка:

State 42000, native 2750, message [Microsoft][ODBC SQL Server Driver][SQL Server]Column or parameter: Specified column precision 38 is greater than the maximum precision of 28.

В MS SQL Server 7.0 максимальная точность для типов NUMERIC и DECIMAL по умолчанию составляет 28 знаков (в отличие от MS SQL 2000 и новее, где предел равен 38). Метапарсер 1С++ для предотвращения переполнения при расчете сумм и остатков по умолчанию разворачивает виртуальные таблицы с точностью 38 разрядов.

Разберем способы обхода этого ограничения:

  1. Настройка параметров запуска службы SQL Server 7.0: в параметрах запуска службы (Startup Parameters) необходимо указать ключ -p38. Этот ключ переключает сервер на поддержку 38-значной точности вычислений. После перезапуска службы ошибка 2750 исчезает.
  2. Отказ от метатаблицы в пользу прямых запросов: если изменить параметры сервера невозможно, вместо виртуальной таблицы $РегистрОстаткиОбороты строим собственный запрос через объединение (UNION ALL) физической таблицы итогов ($РегистрИтоги.ИмяРегистра) и таблицы движений ($Регистр.ИмяРегистра). Это дает полный контроль над типами данных и разрядностью полей.

Применение корректного синтаксиса вызова УложитьСписокОбъектов, правильная типизация параметров через УстПараметр и учет ограничений разрядности числовых полей СУБД обеспечивают стабильную работу прямых запросов 1С++ на любых конфигурациях SQL Server.

← На главную