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