В практике разработки на платформе 1С:Предприятие иногда встречаются регистры накопления с нетипичной структурой. Рассмотрим ситуацию, когда последовательные этапы производства или переделы фиксируются в одном регистре через разные измерения. Например, приход по Измерению 1 и расход по Измерению 2 в одной транзакции, затем приход по Измерению 2 и расход по Измерению 3 в другой. Перед разработчиком встает задача: как превратить эту горизонтальную структуру в красивое вертикальное дерево (иерархию), где каждый последующий этап вложен в предыдущий.
Проанализируем ситуацию: стандартный запрос к виртуальной таблице остатков или оборотов выдаст нам строку, где заполнены лишь некоторые колонки. Для построения иерархии нам нужно привести эти данные к единому виду. Разберем пошагово, как это реализовать.
Первый и самый надежный способ — это нормализация данных внутри самого запроса. Если нам нужно вывести значения разных измерений в одну колонку, мы должны «развернуть» таблицу. Мы создадим запрос, который выбирает каждое измерение по отдельности и объединяет их в общий результат.
Рассмотрим пример построения такого запроса:
ВЫБРАТЬ
Регистр.Измерение1 КАК ЗначениеИзмерения,
"Этап 1" КАК НазваниеЭтапа,
Регистр.СуммаПриход КАК Сумма
ИЗ
РегистрНакопления.ВашРегистр.Обороты КАК Регистр
ГДЕ
Регистр.Измерение1 <> ЗНАЧЕНИЕ(Справочник.ВашСправочник.ПустаяСсылка)
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Регистр.Измерение2,
"Этап 2",
Регистр.СуммаПриход
ИЗ
РегистрНакопления.ВашРегистр.Обороты КАК Регистр
ГДЕ
Регистр.Измерение2 <> ЗНАЧЕНИЕ(Справочник.ВашСправочник.ПустаяСсылка)
Этот подход позволяет нам собрать все значимые данные в одну колонку ЗначениеИзмерения. После этого в системе компоновки данных (СКД) мы сможем легко сгруппировать результат по этой колонке.
Если структура данных позволяет рассматривать измерения как уровни вложенности, мы можем использовать стандартный механизм итогов в языке запросов 1С. Это особенно полезно, когда мы хотим видеть количественные показатели на каждом уровне иерархии.
Проанализируем пример запроса с использованием итогов:
ВЫБРАТЬ
Измерение5,
Измерение4,
Измерение3,
Измерение2,
Измерение1,
СуммаОстаток
ИЗ
РегистрНакопления.ВашРегистр.Остатки
ИТОГИ
СУММА(СуммаОстаток)
ПО
Измерение5,
Измерение4,
Измерение3,
Измерение2,
Измерение1
Важный момент: при таком подходе, если в записи заполнены только Измерение 1 и Измерение 2, а остальные пустые, в отчете могут появиться пустые уровни группировок. Чтобы этого избежать, в настройках СКД или при обработке результата запроса необходимо установить флаг «Игнорировать пустые значения» или использовать отбор в самом запросе.
Если мы работаем в современной версии платформы, наиболее элегантным решением будет использование группировок в СКД. Мы можем не использовать сложные конструкции ИТОГИ ПО в тексте запроса, а настроить иерархию непосредственно в схеме компоновки.
Измерению 5, внутрь нее помещаем группировку по Измерению 4, далее по Измерению 3 и так далее.Выясним причину, почему этот способ часто оказывается предпочтительнее: СКД автоматически оптимизирует запросы к базе данных и корректно обрабатывает пустые ссылки в измерениях, не создавая лишних пустых строк в отчете, если правильно настроены ресурсы.
Рассмотрим ситуацию с точки зрения производительности системы. Использование регистра накопления, в котором в одной записи заполнено 5 измерений, а в другой — другие 5, является серьезным вызовом для СУБД. Проанализируем последствия:
Во-первых, таблица итогов регистра (_AccumRegTotals) будет расти очень быстро. Система создает уникальную запись для каждой комбинации измерений. Поскольку у нас много пустых значений, количество уникальных комбинаций может стать огромным, что замедлит получение остатков.
Во-вторых, при большом количестве объединений (UNION) в запросе, MS SQL Server может столкнуться с проблемой распараллеливания, что иногда приводит к блокировкам типа intra-query parallelism deadlocks. Чтобы этого избежать, старайтесь не делать слишком много объединений в одном запросе. Если уровней передела больше 10, лучше использовать временные таблицы для предварительного сбора данных.
Рекомендация по рефакторингу: если вы столкнулись с такой задачей, стоит задуматься об изменении структуры. Вместо пяти измерений Измерение 1...5, правильнее использовать одно измерение Партия (ссылка на справочник). В самом справочнике Партии можно организовать иерархию (ссылка на родительскую партию). Тогда отчет по всей цепочке производства будет строиться по одному измерению с использованием стандартной иерархии справочника, что работает значительно быстрее.
Мы разобрали три основных способа построения вертикального отчета. Выбор конкретного метода зависит от ваших требований к производительности и сложности структуры данных. В большинстве случаев комбинация UNION ALL во временную таблицу и последующая группировка в СКД дает наиболее предсказуемый и управляемый результат.