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

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

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

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

Причина дублирования строк при выборке через условие ВЫБОР

Проанализируем исходный запрос, в котором создается временная таблица. Для разделения значений свойств по колонкам разработчик применил конструкцию ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ 0 КОНЕЦ:


ВЫБРАТЬ
    ЗначенияСвойствОбъектов.Объект КАК ДоговорЛизинга,
    ВЫБОР
        КОГДА ЗначенияСвойствОбъектов.Свойство.Наименование ПОДОБНО "Стоимость предмета лизинга"
            ТОГДА ВЫРАЗИТЬ(ЗначенияСвойствОбъектов.Значение КАК ЧИСЛО(15, 2))
        ИНАЧЕ 0
    КОНЕЦ КАК СтоимостьПредметаЛизинга,
    ВЫБОР
        КОГДА ЗначенияСвойствОбъектов.Свойство.Наименование ПОДОБНО "Оплачено по договору лизинга"
            ТОГДА ВЫРАЗИТЬ(ЗначенияСвойствОбъектов.Значение КАК ЧИСЛО(15, 2))
        ИНАЧЕ 0
    КОНЕЦ КАК Оплаченоподоговорулизинга
ПОМЕСТИТЬ втРучнаяСтоимостьПредметаЛизинга
ИЗ
    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
ГДЕ
    ЗначенияСвойствОбъектов.Свойство В
            (ВЫБРАТЬ
                СвойстваОбъектов.Ссылка
            ИЗ
                ПланВидовХарактеристик.СвойстваОбъектов КАК СвойстваОбъектов
            ГДЕ
                СвойстваОбъектов.Наименование ПОДОБНО "Стоимость предмета лизинга"
                ИЛИ СвойстваОбъектов.Наименование ПОДОБНО "Оплачено по договору лизинга")
;

В регистре сведений каждая запись хранит только одно свойство объекта. Если у договора заполнены оба свойства, запрос вернет две записи:

  1. В первой строке будет заполнена колонка СтоимостьПредметаЛизинга, а в колонке Оплаченоподоговорулизинга будет 0.
  2. Во второй строке колонка СтоимостьПредметаЛизинга будет содержать 0, а Оплаченоподоговорулизинга — фактическую сумму.

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

Решение 1: Использование условной агрегации (СУММА + ВЫБОР + СГРУППИРОВАТЬ ПО)

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


ВЫБРАТЬ 
    ЗначенияСвойствОбъектов.Объект КАК ДоговорЛизинга, 
    СУММА(ВЫБОР 
        КОГДА ЗначенияСвойствОбъектов.Свойство.Наименование ПОДОБНО "Стоимость предмета лизинга" 
            ТОГДА ВЫРАЗИТЬ(ЗначенияСвойствОбъектов.Значение КАК ЧИСЛО(15, 2))
        ИНАЧЕ 0
    КОНЕЦ) КАК СтоимостьПредметаЛизинга,
    СУММА(ВЫБОР
        КОГДА ЗначенияСвойствОбъектов.Свойство.Наименование ПОДОБНО "Оплачено по договору лизинга" 
            ТОГДА ВЫРАЗИТЬ(ЗначенияСвойствОбъектов.Значение КАК ЧИСЛО(15, 2))
        ИНАЧЕ 0
    КОНЕЦ) КАК Оплаченоподоговорулизинга
ПОМЕСТИТЬ втРучнаяСтоимостьПредметаЛизинга
ИЗ
    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
ГДЕ
    ЗначенияСвойствОбъектов.Свойство В
            (ВЫБРАТЬ
                СвойстваОбъектов.Ссылка
            ИЗ
                ПланВидовХарактеристик.СвойстваОбъектов КАК СвойстваОбъектов
            ГДЕ 
                СвойстваОбъектов.Наименование ПОДОБНО "Стоимость предмета лизинга" 
                ИЛИ СвойстваОбъектов.Наименование ПОДОБНО "Оплачено по договору лизинга") 
СГРУППИРОВАТЬ ПО 
    ЗначенияСвойствОбъектов.Объект
;

Как это работает: для одного и того же договора СУБД складывает значение свойства (например, 100 000) и значение 0 из второй строки. В результате получается одна строка с заполненными числовыми полями по всем требуемым свойствам.

Решение 2: Левые соединения вместо группировки

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


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

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

Решение 3: Штатный механизм характеристик в СКД

Если данные подготавливаются для формирования отчета через систему компоновки данных (СКД), ручной разворот свойств в тексте запроса часто является избыточным:

  1. В СКД встроен штатный механизм работы с характеристиками. На вкладке «Наборы данных» схемы компоновки можно настроить источник характеристик (указать регистр ЗначенияСвойствОбъектов, поле объекта, поле свойства и поле значения).
  2. После настройки платформы все свойства автоматически станут доступны в списке полей компоновщика, и пользователь сможет выводить их в отчет как отдельные колонки без ручного редактирования текста запроса.

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

Разберем несколько критических моментов, влияющих на надежность и производительность запросов:

  1. Ошибки при использовании оператора ПОДОБНО: Конструкция ПОДОБНО "Текст" без спецсимволов маски (% или _) работает в точности как обычное равенство (=). Если требуется учесть возможные лишние пробелы или вариации написания, маску необходимо указывать явно: ПОДОБНО "%Стоимость предмета лизинга%".
  2. Отказ от поиска по наименованию: Поиск свойств по строковым наименованиям в коде запроса ненадежен. При переименовании свойства пользователями логика отчета нарушится. Рекомендуется использовать предопределенные элементы планов видов характеристик либо передавать ссылки на свойства через параметры запроса (&Свойство1, &Свойство2).
  3. Безопасное приведение типов: Поскольку ресурс Значение имеет составной тип, при несовпадении типов функция ВЫРАЗИТЬ вернет значение NULL. Чтобы исключить ошибки при сложении, оборачивайте приведение типов в функцию ЕСТЬNULL(): ЕСТЬNULL(ВЫРАЗИТЬ(Значение КАК ЧИСЛО(15, 2)), 0).
  4. Индексация временных таблиц: Если временная таблица втРучнаяСтоимостьПредметаЛизинга в дальнейшем участвует в соединениях, обязательно добавьте директиву:
    
    ИНДЕКСИРОВАТЬ ПО
        ДоговорЛизинга
    
    Это предотвратит полное сканирование таблицы и ускорит выполнение всего пакетного запроса.
← На главную