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

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

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

Анализ распространенных ошибок при выборке свойств

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

  1. Несоответствие типов данных в параметрах отбора. Распространенная ошибка — передача ссылки на план видов характеристик в параметр, который в тексте запроса сравнивается со строковым полем Наименование. Если написать ЗначенияСвойствОбъектов.Свойство.Наименование = &Наименование1, а в коде передать результат работы ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Группа 1"), то условие будет сравнивать строку со ссылкой. В результате условие вернет Ложь для всех строк, и выборка окажется абсолютно пустой. Сравнивать всегда следует однотипные данные: ссылку со ссылкой (Свойство = &Свойство) либо строку со строкой.
  2. Неверное поле соединения таблиц. В регистре сведений ЗначенияСвойствОбъектов измерение Объект содержит ссылку на владельца свойства (в данном случае на элемент справочника Номенклатура), а ресурс Значение содержит само значение свойства. Если написать условие соединения ПО Номенклатура.Ссылка = ВТ_ЗначениеСвойств.Значение, то платформа пытается сопоставить номенклатуру со значением свойства (которое может быть числом, строкой или элементом другого справочника). Корректным полем для связи всегда является измерение Объект: ПО Номенклатура.Ссылка = ВТ_ЗначениеСвойств.Объект.
  3. Избыточное усложнение через множество временных таблиц. Создание отдельной временной таблицы под каждое свойство сильно загромождает код запроса, снижает его читаемость и усложняет отладку.

Вариант 1. Разворачивание свойств через множественные левые соединения

Рассмотрим прямое и наглядное решение, при котором к основной таблице номенклатуры несколько раз левым соединением подключается таблица регистра сведений. Чтобы избежать задвоения строк, условие отбора конкретного свойства выносится непосредственно в секцию связи таблиц ПО.

Посмотрим на пример такого запроса:


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

Заполнение параметров во встроенном языке в этом случае выглядит следующим образом:


Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
Запрос.УстановитьПараметр("Свойство1", ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Группа 1"));
Запрос.УстановитьПараметр("Свойство2", ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Группа 2"));
Запрос.УстановитьПараметр("Свойство3", ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Группа 3"));
Запрос.УстановитьПараметр("Свойство4", ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Группа 4"));
Запрос.УстановитьПараметр("Свойство5", ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Группа 5"));

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

Вариант 2. Оптимальное решение через агрегацию и группировку (ВЫБОР ... КОГДА)

Если планируется формировать выборку по всей номенклатуре или большому списку позиций, использование пяти и более последовательных левых соединений одной и той же физической таблицы может вызвать серьезные проблемы с производительностью СУБД. Оптимизатор запросов СУБД будет строить сложные вложенные циклы (Nested Loops), что существенно замедлит выполнение.

Разберем по шагам более производительный архитектурный паттерн: одно левое соединение со списком свойств и последующее разворачивание строк через конструкцию ВЫБОР КОГДА ... ТОГДА с группировкой по функции МАКСИМУМ.


ВЫБРАТЬ
    Номенклатура.Код КАК Код,
    Номенклатура.Ссылка КАК Номенклатура,
    Номенклатура.БазоваяЕдиницаИзмерения КАК БазоваяЕдиницаИзмерения,
    Номенклатура.ВидНоменклатуры КАК ВидНоменклатуры,
    МАКСИМУМ(ВЫБОР
            КОГДА Свойства.Свойство = &Свойство1
                ТОГДА Свойства.Значение
        КОНЕЦ) КАК Значение1,
    МАКСИМУМ(ВЫБОР
            КОГДА Свойства.Свойство = &Свойство2
                ТОГДА Свойства.Значение
        КОНЕЦ) КАК Значение2,
    МАКСИМУМ(ВЫБОР
            КОГДА Свойства.Свойство = &Свойство3
                ТОГДА Свойства.Значение
        КОНЕЦ) КАК Значение3,
    МАКСИМУМ(ВЫБОР
            КОГДА Свойства.Свойство = &Свойство4
                ТОГДА Свойства.Значение
        КОНЕЦ) КАК Значение4,
    МАКСИМУМ(ВЫБОР
            КОГДА Свойства.Свойство = &Свойство5
                ТОГДА Свойства.Значение
        КОНЕЦ) КАК Значение5
ИЗ
    Справочник.Номенклатура КАК Номенклатура
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК Свойства
            ПО Номенклатура.Ссылка = Свойства.Объект
            И Свойства.Свойство В (&СписокСвойств)
ГДЕ
    Номенклатура.Ссылка = &Номенклатура
    И НЕ Номенклатура.ЭтоГруппа

СГРУППИРОВАТЬ ПО
    Номенклатура.Код,
    Номенклатура.Ссылка,
    Номенклатура.БазоваяЕдиницаИзмерения,
    Номенклатура.ВидНоменклатуры

В этом варианте для условия соединения достаточно передать один массив со всеми требуемыми свойствами в параметр &СписокСвойств, что упрощает управление запросом из кода 1С:


СписокСвойств = Новый Массив;
СписокСвойств.Добавить(Свойство1);
СписокСвойств.Добавить(Свойство2);
СписокСвойств.Добавить(Свойство3);
СписокСвойств.Добавить(Свойство4);
СписокСвойств.Добавить(Свойство5);

Запрос.УстановитьПараметр("СписокСвойств", СписокСвойств);
Запрос.УстановитьПараметр("Свойство1", Свойство1);
Запрос.УстановитьПараметр("Свойство2", Свойство2);
Запрос.УстановитьПараметр("Свойство3", Свойство3);
Запрос.УстановитьПараметр("Свойство4", Свойство4);
Запрос.УстановитьПараметр("Свойство5", Свойство5);

Важные практические рекомендации

  1. Проверяйте архитектуру хранения свойств в конфигурации. В типовых конфигурациях на платформе 1С:Предприятие 8 существуют разные механизмы хранения:
    • В старых редакциях (например, УТ 10.3, УПП 1.3) свойства хранятся в регистре ЗначенияСвойствОбъектов.
    • В современных решениях на базе Библиотеки стандартных подсистем (УТ 11, ERP, КА, БП 3.0) дополнительные реквизиты хранятся непосредственно в табличной части самого объекта Номенклатура.ДополнительныеРеквизиты, а в регистре сведений ДополнительныеРеквизитыИСведения хранятся только дополнительные сведения. Попытка прочитать дополнительный реквизит из регистра сведений в современных конфигурациях вернет пустой результат.
  2. Откажитесь от поиска по наименованию в боевом коде. Метод НайтиПоНаименованию() крайне чувствителен к случайным пробелам, опечаткам и действиям пользователей. Если пользователь отредактирует наименование свойства в режиме предприятия, код перестанет находить элемент и в запрос передастся пустая ссылка Неопределено. Надежнее использовать предопределенные элементы, поиск по уникальному идентификатору (GUID) или выносить выбор анализируемых свойств в реквизиты обработки или настройки отчета.
  3. Учитывайте составной тип поля «Значение». Поле Значение в регистре свойств обычно имеет составной тип. Если тип значения свойства заранее известен (например, ссылка на Справочник.ЗначенияСвойствОбъектов), рекомендуется использовать функцию ВЫРАЗИТЬ(Свойства.Значение КАК Справочник.ЗначенияСвойствОбъектов), чтобы снизить нагрузку на СУБД при операциях группировки.
  4. Используйте СКД для вывода в отчеты. Если целью является аналитический отчет, нет необходимости вручную прописывать колонки в запросе. Достаточно выбрать плоскую таблицу полей Номенклатура, Свойство, Значение и в структуре отчета Системы компоновки данных создать таблицу, где строками будет выступать номенклатура, колонками — свойства, а ресурсом — само значение. СКД динамически сформирует все нужные колонки автоматически.
← На главную