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