Как в запросе 1С получить список тегов для номенклатуры в одной строке

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

При разработке отчетов или механизмов обработки данных в 1С мы часто сталкиваемся с ситуацией, когда одному объекту (например, Номенклатура) соответствует множество записей в другом справочнике или регистре (например, Теги или ДополнительныеРеквизиты). Стандартное левое соединение в обычном запросе приводит к тому, что номенклатура дублируется столько раз, сколько тегов к ней привязано. Это неудобно для вывода в отчеты или списки. В этой статье мы разберем, как обойти это ограничение и получить данные в структурированном виде: одна строка — одна номенклатура — список всех её тегов.

Почему обычный запрос не возвращает коллекцию значений

Прежде всего, проанализируем ситуацию с точки зрения теории баз данных. Язык запросов 1С основан на SQL, который работает с плоскими таблицами. Когда мы выполняем ЛЕВОЕ СОЕДИНЕНИЕ, система строит декартово произведение. Если у товара 10 тегов, в результате запроса будет 10 строк. Многие начинающие разработчики пытаются использовать синтаксис вложенных таблиц, который выглядит так:


ВЫБРАТЬ
    Номенклатура.Ссылка,
    Номенклатура.Состав.(
        Материал,
        Количество
    )
ИЗ
    Справочник.Номенклатура КАК Номенклатура

Важно понимать: этот синтаксис работает только для табличных частей самого объекта. Мы не можем применить его к произвольному соединению двух разных справочников. Платформа 1С не позволяет динамически создавать структуру РезультатЗапроса внутри колонки другого запроса при соединении сторонних таблиц. Однако, у нас есть как минимум три эффективных способа решить эту задачу.

Способ №1: Использование СКД и функции СоединитьСтроки

Рассмотрим наиболее современный и простой вариант, если ваша цель — вывод данных в отчет. Система компоновки данных (СКД) обладает мощным механизмом агрегатных функций, которые работают уже после получения данных из базы. Выясним, как это настроить по шагам:

  1. Создадим набор данных - запрос, где просто соединим номенклатуру и теги. Да, в самом запросе данные будут дублироваться, но СКД это исправит.
  2. Перейдем на закладку "Ресурсы".
  3. Выберем поле Тег. В колонке "Выражение" пропишем специальную функцию: СоединитьСтроки(Массив(Тег), ", ").
  4. В колонке "Рассчитывать по..." укажем поле Номенклатура.

Посмотрим на результат: СКД автоматически сгруппирует все теги, поместит их в массив, а затем склеит в одну красивую строку через запятую. Это идеальный вариант для визуализации данных пользователю.

Способ №2: Программный обход результата с итогами

Если данные нужны нам не для отчета, а для программной обработки (например, для выгрузки в JSON или заполнения таблицы значений), мы воспользуемся конструкцией ИТОГИ. Проанализируем пример кода:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Теги.Номенклатура КАК Номенклатура,
    |   Теги.Тег КАК Тег
    |ИЗ
    |   Справочник.Теги КАК Теги
    |ИТОГИ ПО
    |   Номенклатура";

РезультатЗапроса = Запрос.Выполнить();

// Выбираем группировку по номенклатуре
ВыборкаНоменклатура = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаНоменклатура.Следующий() Цикл
    
    // Для каждой номенклатуры получаем её вложенные записи (теги)
    ВыборкаТеги = ВыборкаНоменклатура.Выбрать();
    
    СписокТегов = "";
    Пока ВыборкаТеги.Следующий() Цикл
        СписокТегов = СписокТегов + ВыборкаТеги.Тег + "; ";
    КонецЦикла;
    
    Сообщить("Товар: " + ВыборкаНоменклатура.Номенклатура + " Теги: " + СписокТегов);
    
КонецЦикла;

В этом примере мы используем иерархический обход. Метод Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам) позволяет нам сначала получить уникальную строку номенклатуры, а затем "провалиться" внутрь и получить только те теги, которые относятся к этой конкретной записи. Это программно имитирует вложенную таблицу значений.

Способ №3: Сложные вычисления в СКД (Массивы и структуры)

Иногда просто склеить строки недостаточно. Бывают задачи, где нужно передать массив объектов во вложенную схему или в макет. В этом случае разберем функцию ВычислитьВыражениеСГруппировкойМассив. Она позволяет собрать коллекцию значений прямо в процессе компоновки.

Пример выражения в ресурсах СКД:

ВычислитьВыражениеСГруппировкойМассив("Тег", "Номенклатура")

Это выражение создаст полноценный объект типа Массив для каждой строки номенклатуры. Это крайне полезно, если в дальнейшем вы планируете передавать эти данные в программный обработчик или использовать в расшифровках отчета.

Рекомендации по оптимизации и Динамическим спискам

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

В таких случаях мы рекомендуем использовать один из двух подходов:

  1. Денормализация данных: Создайте у справочника Номенклатура строковый реквизит ВсеТегиСтрокой. При записи тега обновляйте это поле. Тогда запрос в динамическом списке будет мгновенным и без соединений.
  2. Событие ПриПолученииДанныхНаСервере: В этом обработчике можно программно дочитать теги для отображаемых на экране строк и вывести их в колонку, не связанную с данными напрямую. Однако это может сказаться на скорости прокрутки списка.

Подведем итог: штатного способа получить "Таблицу значений в ячейке" через простой запрос не существует из-за архитектуры СУБД. Но, используя возможности СКД для отчетов и ИТОГИ для программного кода, мы можем эффективно решать задачи любой сложности по агрегации подчиненных данных.

← На главную