Почему возникает ошибка «Тип не может быть выбран в запросе» в 1С и как её исправить?

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

При разработке сложных отчетов или алгоритмов проведения документов разработчики 1С часто передают в запрос объект ТаблицаЗначений в качестве параметра для последующего помещения во временную таблицу. Однако в некоторых случаях при вызове метода Выполнить() система аварийно завершает операцию с ошибкой «Тип не может быть выбран в запросе» (или аналогичной ошибкой трансляции типов). Разберем причины такого поведения платформы и детально рассмотрим способы устранения проблемы.

Проанализируем типичный пример кода, на котором воспроизводится данная ситуация:


Запрос = Новый Запрос;
МенеджерВремТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.МенеджерВременныхТаблиц = МенеджерВремТаблиц;

Запрос.Текст = 
"ВЫБРАТЬ РАЗЛИЧНЫЕ
|   Таб.Сделка КАК Сделка,
|   Таб.ДокументРасчетовСКонтрагентом КАК ДокументРасчетовСКонтрагентом
|ПОМЕСТИТЬ ТаблицаВзаиморасчетов
|ИЗ
|   &ТаблицаВзаиморасчетов КАК Таб
|ГДЕ
|   НЕ Таб.ДокументРасчетовСКонтрагентом = &Ссылка";

Запрос.УстановитьПараметр("ТаблицаВзаиморасчетов", ТаблицаВзаиморасчетов);
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Запрос.Выполнить();

На первый взгляд код выглядит корректным: таблица типизирована, битых ссылок нет, в отладчике все значения заполнены. Выясним причину, почему платформа 1С выдает ошибку при обращении к типизированным полям.

Внутренний механизм передачи ТаблицыЗначений в СУБД

Когда мы передаем таблицу значений в запрос с конструкцией ПОМЕСТИТЬ, платформа 1С транслирует переданный массив данных в реальную временную таблицу СУБД (например, в системную базу tempdb на MS SQL Server или аналогичное хранилище в PostgreSQL). Для каждой колонки составного типа платформа на уровне СУБД формирует служебные поля:

  1. Колонку с кодом типа данных (..._TYPE).
  2. Колонку с идентификатором ссылки или значения (..._IDRRef).

Если поле таблицы значений имеет широкий составной тип (например, реквизит ДокументРасчетовСКонтрагентом, включающий ссылки на десятки или сотни видов документов конфигурации), платформа при создании временной таблицы в СУБД обязана сопоставить метаданные для каждого входящего в состав типа. Ошибка «Тип не может быть выбран в запросе» возникает в следующих ситуациях:

  1. Нарушение целостности метаданных («фантомные» типы). Если после обновления конфигурации или объединения релизов один из видов документов был удален или переименован, но его внутренний идентификатор остался в определяемом типе, критерии отбора или кэше конфигурации, транслятор типов 1С не может корректно создать структуру таблицы на сервере СУБД. При попытке выбрать такой тип в интерфейсе платформа нередко аварийно завершает работу.
  2. Превышение ограничений транслятора и СУБД. При слишком большом количестве ссылочных типов в одной колонке количество создаваемых полей и внутренних связей для трансляции запроса может превысить пределы СУБД или механизмов платформы.
  3. Недопустимые типы данных. В колонке таблицы присутствуют типы, которые платформа не поддерживает при передаче через параметры запроса во временную таблицу: УникальныйИдентификатор, ХранилищеЗначения, ДвоичныеДанные, Неопределено (когда колонка содержит произвольный тип данных без явного описания).

Способ 1. Сужение типов через программную дотипизацию таблицы

Самый быстрый и надежный способ устранить ошибку на уровне кода — сформировать для проблемной колонки явное ОписаниеТипов, содержащее только те типы данных, которые действительно присутствуют в переданной таблице. Разберем, как это реализовать на практике:


// 1. Создаем пустую таблицу-копию структуры
ТаблицаДляЗапроса = ТаблицаВзаиморасчетов.СкопироватьКолонки();

// 2. Собираем массив только фактически используемых типов из строк таблицы
МассивТипов = Новый Массив;
Для Каждого Стр Из ТаблицаВзаиморасчетов Цикл
    ТекущийТип = ТипЗнч(Стр.ДокументРасчетовСКонтрагентом);
    Если МассивТипов.Найти(ТекущийТип) = Неопределено И ТекущийТип <> Тип("Неопределено") Тогда
        МассивТипов.Добавить(ТекущийТип);
    КонецЕсли;
КонецЦикла;

// 3. Переопределяем состав типов у колонки
ТаблицаДляЗапроса.Колонки.Удалить("ДокументРасчетовСКонтрагентом");
ТаблицаДляЗапроса.Колонки.Добавить("ДокументРасчетовСКонтрагентом", Новый ОписаниеТипов(МассивТипов));

// 4. Заполняем данные
Для Каждого Стр Из ТаблицаВзаиморасчетов Цикл
    ЗаполнитьЗначенияСвойств(ТаблицаДляЗапроса.Добавить(), Стр);
КонецЦикла;

// 5. Передаем в запрос подготовленную таблицу
Запрос.УстановитьПараметр("ТаблицаВзаиморасчетов", ТаблицаДляЗапроса);

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

Способ 2. Ограничение типа оператором ВЫРАЗИТЬ в тексте запроса

Если перечень возможных типов заранее известен и не велик, мы можем ограничить составной тип непосредственно в тексте запроса. Посмотрим на пример явного приведения типов:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Таб.Сделка КАК Сделка,
    ВЫБОР
        КОГДА Таб.ДокументРасчетовСКонтрагентом ССЫЛКА Документ.РеализацияТоваровУслуг
            ТОГДА ВЫРАЗИТЬ(Таб.ДокументРасчетовСКонтрагентом КАК Документ.РеализацияТоваровУслуг)
        КОГДА Таб.ДокументРасчетовСКонтрагентом ССЫЛКА Документ.ПоступлениеТоваровУслуг
            ТОГДА ВЫРАЗИТЬ(Таб.ДокументРасчетовСКонтрагентом КАК Документ.ПоступлениеТоваровУслуг)
        ИНАЧЕ НЕОПРЕДЕЛЕНО
    КОНЕЦ КАК ДокументРасчетовСКонтрагентом
ПОМЕСТИТЬ ТаблицаВзаиморасчетов
ИЗ
    &ТаблицаВзаиморасчетов КАК Таб

Такой подход помогает оптимизировать план запроса на стороне СУБД и снимает избыточную нагрузку на транслятор метаданных.

Способ 3. Исправление структуры метаданных и серверного кэша

Если ранее код работал стабильно, а ошибка появилась внезапно после обновления конфигурации или добавления/удаления объектов, причиной является рассинхронизация таблиц описания типов в базе данных. Выполним следующие шаги для восстановления корректной работы:

  1. Пересоздание удаленного типа метаданных. Если в конфигурации был удален документ, на который ссылались общие типы: добавьте в конфигураторе фиктивный документ с тем же именем, сохраните и обновите конфигурацию базы данных, затем удалите его повторно и вновь выполните обновление. Это заставит платформу корректно очистить внутренние ссылки из всех коллекций типов.
  2. Очистка серверного кэша. Завершите рабочие процессы кластера серверов 1С:Предприятия, очистите каталоги временных файлов сервера и кэш сеансов. При динамическом («демоническом») обновлении рабочий процесс может продолжать удерживать устаревшую карту метаданных.
  3. Тестирование и исправление информационной базы. В режиме Конфигуратора запустите процедуру Администрирование -> Тестирование и исправление... со следующими обязательными флагами:
    1. Проверка логической целостности информационной базы.
    2. Проверка ссылочной целостности информационной базы.
    3. Реструктуризация таблиц информационной базы.
  4. Выгрузка и загрузка базы данных. Выполните выгрузку базы в файл .dt и восстановите её в чистую информационную базу. В процессе загрузки структуры таблиц конфигурации пересобираются «с нуля», что гарантированно устраняет артефакты в таблицах описания метаданных.

Применение дотипизации колонок в связке с регулярным контролем целостности структуры метаданных позволяет полностью избежать ошибок трансляции типов при работе с временными таблицами в запросах 1С.

← На главную