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