Как получить свойства номенклатуры в виде вложенной таблицы в запросе 1С?

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

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

Ограничение языка запросов платформы 1С

Посмотрим на синтаксис, который разработчики часто пытаются применить по аналогии с табличными частями документов или справочников:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка,
    ЗначенияСвойствОбъектов.(Свойство, Значение) КАК СвойстваНоменклатуры
ИЗ
    Справочник.Номенклатура КАК Номенклатура
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
        ПО Номенклатура.Ссылка = ЗначенияСвойствОбъектов.Объект

При выполнении такого запроса платформа выдаст синтаксическую ошибку. Выясним причину такого поведения системы. Конструкция вида ИмяТаблицы.(Поле1, Поле2) доступна исключительно для подчиненных таблиц — табличных частей прикладных объектов (справочников, документов, отчетов и др.).

На уровне базы данных табличная часть жестко привязана к ссылке родительского объекта через внутреннее поле Ссылка. Независимый регистр сведений (такой как РегистрСведений.ЗначенияСвойствОбъектов) не является встроенной табличной частью справочника. Он представляет собой самостоятельную сущность СУБД, связь с которой задается динамически через условие соединения. По этой причине преобразовать строки регистра сведений во вложенную таблицу непосредственно в блоке ВЫБРАТЬ невозможно.

Вариант 1. Табличные части в механизме дополнительных реквизитов БСП

Проанализируем конфигурации, разработанные на базе Библиотеки Стандартных Подсистем (БСП). В них свойства объектов разделены на две категории:

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

Если в вашей системе свойства номенклатуры настроены именно как дополнительные реквизиты, мы можем получить вложенную таблицу прямым обращением к табличной части:


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

При выгрузке результата такого запроса методом Запрос.Выполнить().Выгрузить() в колонке СвойстваНоменклатуры действительно будет находиться отдельная таблица значений для каждой строки номенклатуры.

Важное предостережение: если вы планируете передавать полученную таблицу значений обратно в запрос как внешнюю таблицу (конструкция ПОМЕСТИТЬ ВТ Из &ВнешняяТЗ), платформа 1С вызовет исключение. Временные таблицы не поддерживают колонки с составными типами и вложенными коллекциями (таблицами значений).

Вариант 2. Использование плоской временной таблицы в пакете запросов

Если данные требуются для дальнейших расчетов внутри одного пакетного запроса, наиболее производительным и архитектурно правильным решением будет отказ от вложенных структур в пользу плоской временной таблицы с индексацией:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Номенклатура,
    ЗначенияСвойствОбъектов.Свойство КАК Свойство,
    ЗначенияСвойствОбъектов.Значение КАК Значение
ПОМЕСТИТЬ ВТ_СвойстваНоменклатуры
ИЗ
    Справочник.Номенклатура КАК Номенклатура
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
        ПО Номенклатура.Ссылка = ЗначенияСвойствОбъектов.Объект
ИНДЕКСИРОВАТЬ ПО
    Номенклатура,
    Свойство;

Такой подход обеспечивает максимальную скорость работы СУБД. В последующих запросах пакета к временной таблице ВТ_СвойстваНоменклатуры можно легко обращаться через левые соединения по полям Номенклатура и Свойство.

Вариант 3. Программная сборка таблицы с вложенными ТЗ во встроенном языке

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

Разберем по шагам реализацию данного алгоритма:

  1. Получаем плоские данные одним запросом без лишних итогов.
  2. Индексируем колонку связи во вспомогательной таблице свойств.
  3. Обходим список уникальной номенклатуры и заполняем вложенные таблицы через быстрый отбор.

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

РезультатыЗапроса = Запрос.ВыполнитьПакет();
ТЗ_Номенклатура = РезультатыЗапроса[0].Выгрузить();
ТЗ_Свойства = РезультатыЗапроса[1].Выгрузить();

// Индексируем колонку для быстрого поиска строк методом НайтиСтроки
ТЗ_Свойства.Индексы.Добавить("Номенклатура");

// Подготавливаем результирующую таблицу
ТЗ_Результат = Новый ТаблицаЗначений;
ТЗ_Результат.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТЗ_Результат.Колонки.Добавить("СвойстваНоменклатуры", Новый ОписаниеТипов("ТаблицаЗначений"));

Отбор = Новый Структура("Номенклатура");

Для Каждого СтрНом Из ТЗ_Номенклатура Цикл
    НоваяСтрока = ТЗ_Результат.Добавить();
    НоваяСтрока.Номенклатура = СтрНом.Номенклатура;
    
    // Создаем структуру вложенной таблицы значений
    ТЗ_Вложенная = Новый ТаблицаЗначений;
    ТЗ_Вложенная.Колонки.Добавить("Свойство");
    ТЗ_Вложенная.Колонки.Добавить("Значение");
    
    Отбор.Номенклатура = СтрНом.Номенклатура;
    НайденныеСтроки = ТЗ_Свойства.НайтиСтроки(Отбор);
    
    Для Каждого СтрСвойство Из НайденныеСтроки Цикл
        ЗаполнитьЗначенияСвойств(ТЗ_Вложенная.Добавить(), СтрСвойство);
    КонецЦикла;
    
    НоваяСтрока.СвойстваНоменклатуры = ТЗ_Вложенная;
КонецЦикла;

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

← На главную