Передача таблицы значений в запрос 1С — частая задача при разработке, когда требуется соединить предварительно рассчитанные в памяти данные с таблицами базы данных или выполнить по ним сложную группировку. Разберем по шагам, как правильно подготовить таблицу значений, передать ее в параметры запроса и обработать на стороне СУБД.
Платформа 1С:Предприятие не позволяет передавать в запрос таблицу значений с произвольными (нетипизированными) колонками. Если создать колонку простым вызовом Таблица.Колонки.Добавить("Номенклатура") без указания второго параметра ОписаниеТипов, при выполнении запроса возникнет ошибка времени выполнения.
Проанализируем требования к типам данных для колонок таблицы значений:
Число, Строка, Дата, Булево), а также ссылочные типы конфигурации (СправочникСсылка, ДокументСсылка, ПеречислениеСсылка и др.). Допускаются и составные типы, если каждый тип в отдельности поддерживается платформой в запросах.СправочникОбъект, ДокументОбъект), коллекции (Массив, Структура, Соответствие) и бинарные данные. Их использование приведет к исключению.КвалификаторыСтроки фиксированной длины. Неограниченные строки переносятся в СУБД как неограниченные поля, что сделает невозможным операции соединения (СОЕДИНЕНИЕ), группировки (СГРУППИРОВАТЬ ПО), отбора уникальных (РАЗЛИЧНЫЕ) и сортировки (УПОРЯДОЧИТЬ ПО).Рассмотрим пример правильного создания типизированной таблицы значений с нуля и передачи ее в запрос:
// 1. Создаем таблицу значений и описываем типы колонок
ТЗ = Новый ТаблицаЗначений;
МассивТиповСсылка = Новый Массив;
МассивТиповСсылка.Добавить(Тип("СправочникСсылка.Номенклатура"));
ОписаниеТипаНоменклатура = Новый ОписаниеТипов(МассивТиповСсылка);
ТЗ.Колонки.Добавить("Номенклатура", ОписаниеТипаНоменклатура);
КвалификаторыЧисла = Новый КвалификаторыЧисла(15, 2, ДопустимыйЗнак.Неотрицательный);
ОписаниеТипаКоличество = Новый ОписаниеТипов("Число", , КвалификаторыЧисла);
ТЗ.Колонки.Добавить("Количество", ОписаниеТипаКоличество);
// 2. Заполняем таблицу данными
НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.Номенклатура = СсылкаНаТовар;
НоваяСтрока.Количество = 10;
// 3. Формируем запрос и передаем таблицу в параметры
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВхТЗ.Номенклатура КАК Номенклатура,
| ВхТЗ.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_ИсходныеДанные
|ИЗ
| &ВнешняяТЗ КАК ВхТЗ
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ.Номенклатура КАК Номенклатура,
| ВТ.Количество КАК Количество,
| ВТ.Номенклатура.Артикул КАК Артикул
|ИЗ
| ВТ_ИсходныеДанные КАК ВТ";
Запрос.УстановитьПараметр("ВнешняяТЗ", ТЗ);
Результат = Запрос.Выполнить();
Если таблица значений уже сформирована сторонним алгоритмом или получена без типизации, метод Скопировать() не решит проблему, так как он просто копирует нетипизированную структуру. В таком случае разберем, как создать типизированную копию вручную:
// Создаем типизированный приемник
ТипизированнаяТЗ = Новый ТаблицаЗначений;
ТипизированнаяТЗ.Колонки.Добавить("Товар", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТипизированнаяТЗ.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число", , Новый КвалификаторыЧисла(15, 2)));
// Переносим данные из исходной нетипизированной таблицы
Для Каждого СтрИсходная Из ИсходнаяТЗ Цикл
ЗаполнитьЗначенияСвойств(ТипизированнаяТЗ.Добавить(), СтрИсходная);
КонецЦикла;
// Передаем типизированную таблицу в запрос
Запрос.УстановитьПараметр("ВнешняяТЗ", ТипизированнаяТЗ);
Выясним важные технические нюансы работы с переданной таблицей значений:
ПОМЕСТИТЬ: переданную через параметр таблицу значений нельзя сразу соединять с другими таблицами базы (например, писать ЛЕВОЕ СОЕДИНЕНИЕ &ВнешняяТЗ). Таблицу необходимо первым пакетом запроса поместить во временную таблицу.ИНДЕКСИРОВАТЬ ПО:
ВЫБРАТЬ
ВхТЗ.Номенклатура КАК Номенклатура,
ВхТЗ.Количество КАК Количество
ПОМЕСТИТЬ ВТ_ИсходныеДанные
ИЗ
&ВнешняяТЗ КАК ВхТЗ
ИНДЕКСИРОВАТЬ ПО
Номенклатура
Посмотрим на альтернативные варианты, которые могут оказаться эффективнее таблицы значений:
ГДЕ Поле В (&МассивСсылок), не используйте таблицу значений — передавайте стандартный Массив.Выгрузить(). Используйте МенеджерВременныхТаблиц, чтобы временная таблица сохранилась в контексте сеанса без лишней нагрузки на оперативную память сервера.