Как правильно передать выделенные строки формы в запрос 1С и избежать ошибки «Тип не может быть выбран в запросе»?

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

При разработке обработок и форм часто возникает необходимость отфильтровать данные в запросе по строкам, выбранным пользователем в табличном поле или динамическом списке. Однако попытка передать программно сформированную таблицу значений в запрос может привести к критической ошибке: «Тип не может быть выбран в запросе». Разберем по шагам, почему возникает эта проблема и как ее правильно решить.

Выясним причину ошибки

Проанализируем ситуацию на основе исходного кода. Ошибка возникает в момент вызова метода Запрос.Выполнить():


{(2, 2)}: Тип не может быть выбран в запросе
<<?>>ТЧПодготовка.Ссылка КАК Ссылка

Рассмотрим две ключевые причины возникновения данного сбоя:

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

Способ 1. Использование массива ссылок (Рекомендуемый вариант)

Если цель запроса — просто отфильтровать данные по выбранным документам или справочникам через условие ГДЕ Ссылка В (&Массив), создавать временную таблицу из таблицы значений не требуется. Намного проще и эффективнее сформировать обычный Массив ссылок.

Рассмотрим пример кода с заполнением массива выделенных элементов:


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

// Получаем выделенные строки из элемента формы
ВыделенныеСтроки = ЭлементыФормы.ТЧДокументы.ВыделенныеСтроки;

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

Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
РезультатЗапроса = Запрос.Выполнить();
Выгрузка = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);

Передача массива напрямую в условие В(&Параметр) выполняется быстро, не требует помещения во временную таблицу и автоматически обрабатывает допустимые типы элементов.

Способ 2. Явная типизация колонки Таблицы Значений

Если логика требует обязательного помещения внешних данных во временную таблицу с помощью конструкции ПОМЕСТИТЬ, необходимо строго задать тип колонки с помощью объекта ОписаниеТипов.

Разберем подробнее, как правильно инициализировать таблицу значений перед передачей в запрос:


// Создаем описание типов для колонки "Ссылка"
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("ДокументСсылка.ПеремещениеТМЦ"));
ОписаниеТипаСсылка = Новый ОписаниеТипов(МассивТипов);

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

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

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
               |	ТЧ.Ссылка КАК Ссылка
               |ПОМЕСТИТЬ ВремТабДокументов
               |ИЗ
               |	&ТЧПараметр КАК ТЧ
               |;
               |////////////////////////////////////////////////////////////////////////////////
               |ВЫБРАТЬ
               |	ПеремещениеТМЦ.Ссылка КАК Ссылка,
               |	ПеремещениеТМЦ.Номенклатура КАК Номенклатура,
               |	ПеремещениеТМЦ.Количество КАК Количество
               |ИЗ
               |	Документ.ПеремещениеТМЦ.ТМЦ КАК ПеремещениеТМЦ
               |ГДЕ
               |	ПеремещениеТМЦ.Ссылка В (ВЫБРАТЬ Т.Ссылка ИЗ ВремТабДокументов КАК Т)";

Запрос.УстановитьПараметр("ТЧПараметр", ТаблицаДляЗапроса);
РезультатЗапроса = Запрос.Выполнить();

Пример вывода иерархического результата в дерево значений

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


Процедура ОбновитьПодготовкуДанных()

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

    ВыделенныеСтроки = ЭлементыФормы.ТЧДокументы.ВыделенныеСтроки;
    
    СписокДокументов = Новый Массив;
    Для Каждого Строка Из ВыделенныеСтроки Цикл
        СписокДокументов.Добавить(Строка);
    КонецЦикла;

    Запрос.УстановитьПараметр("СписокДокументов", СписокДокументов);
    
    // Выгрузка результата с сохранением иерархии группировок
    Выгрузка = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
    
    // Привязка данных к реквизиту формы
    ТЧПодготовка = Выгрузка;
    ЭлементыФормы.ТЧПодготовка.СоздатьКолонки();

КонецПроцедуры

Процедура ТЧПодготовкаПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    
    ТекущаяСтрока = ЭлементыФормы.ТЧДокументы.ТекущаяСтрока;
    
    // Подсветка строк текущего активного документа
    Если ДанныеСтроки.Ссылка = ТекущаяСтрока Тогда
        ОформлениеСтроки.ЦветТекста = WebЦвета.Черный;
        ОформлениеСтроки.ЦветФона = WebЦвета.БледноЗеленый;
    КонецЕсли;

КонецПроцедуры

Подводя итог: при передаче списков в запрос отдавайте предпочтение объекту Массив. Если же необходимо использовать ТаблицаЗначений для создания временных таблиц через ПОМЕСТИТЬ, всегда явно задавайте типы данных с помощью ОписаниеТипов при добавлении колонок.

← На главную