При разработке сложных отчетов в системе компоновки данных (СКД) часто возникает задача объединения данных из нескольких регистров накопления. Типичная ситуация: один регистр хранит складские остатки в розничных ценах, а другой — в закупочных ценах с детализацией по партиям. Основная трудность заключается в том, что при простом объединении запросов или наборов данных начальные и конечные остатки начинают «удваиваться», «обнуляться» или выводиться некорректно, особенно если в отчет добавляется поле Регистратор.
В этой статье мы подробно разберем, почему возникают ошибки при расчете остатков и как настроить СКД, чтобы получить правильный результат по всем ресурсам. Мы проанализируем методики настройки ролей полей, работу с виртуальными таблицами и особенности связей наборов данных.
Разберем ситуацию: у нас есть два регистра. Первый содержит измерения Склад и Номенклатура, а второй — Склад, Номенклатура и Партия. Ресурс Количество присутствует в обоих. Когда мы пытаемся соединить эти таблицы, СКД должна сопоставить записи. Если мы используем ОБЪЕДИНИТЬ ВСЕ в одном запросе, система получает набор строк, где часть колонок заполнена для одного регистра, а часть — для другого.
Проблема «кривых» остатков чаще всего связана с тем, что механизм компоновки не понимает, что НачальныйОстаток из первого регистра и НачальныйОстаток из второго регистра — это по сути одна и та же логическая сущность, которую нужно суммировать, а не выводить отдельными строками или затирать. Еще сложнее ситуация становится при выводе поля Регистратор, так как остатки должны рассчитываться на каждый момент времени (момент документа).
Проанализируем настройку ролей на закладке «Наборы данных». Это ключевой инструмент, позволяющий СКД правильно «схлопывать» остатки из разных источников. Рассмотрим шаги по настройке:
Кол. Это скажет СКД: «Сложи эти данные в одну колонку остатка».Кол.Склад и Номенклатура.Если эти настройки выполнены верно, то даже если данные приходят из разных запросов или наборов данных, СКД сможет корректно рассчитать итоги по группировкам.
Рассмотрим, как должен выглядеть запрос, если мы решили использовать ОБЪЕДИНИТЬ ВСЕ. Важно привести структуру полей к единому виду. Если во втором регистре есть Партия, а в первом — нет, мы должны создать «пустое» поле в первом запросе, чтобы структура таблиц совпала.
Посмотрим на пример структуры запроса:
ВЫБРАТЬ
Т1.Склад КАК Склад,
Т1.Номенклатура КАК Номенклатура,
ЗНАЧЕНИЕ(Документ.ПоступлениеТоваровУслуг.ПустаяСсылка) КАК Партия,
Т1.КоличествоНачальныйОстаток КАК КоличествоНачОст,
Т1.КоличествоПриход КАК КоличествоПриход,
Т1.КоличествоРасход КАК КоличествоРасход,
Т1.КоличествоКонечныйОстаток КАК КоличествоКонОст,
Т1.СуммаРознОборот КАК СуммаРозн,
0 КАК СуммаЗакуп
ИЗ
РегистрНакопления.РозничныеПродажи.ОстаткиИОбороты({&НачалоПериода}, {&КонецПериода}, Авто, , ) КАК Т1
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Т2.Склад,
Т2.Номенклатура,
Т2.Партия,
Т2.КоличествоНачальныйОстаток,
Т2.КоличествоПриход,
Т2.КоличествоРасход,
Т2.КоличествоКонечныйОстаток,
0,
Т2.СуммаЗакупОборот
ИЗ
РегистрНакопления.ЗакупкиПоПартиям.ОстаткиИОбороты({&НачалоПериода}, {&КонецПериода}, Авто, , ) КАК Т2
Важно: Обратите внимание на использование фигурных скобок {} вокруг параметров &НачалоПериода и &КонецПериода. Это позволяет СКД самостоятельно управлять границами периода виртуальных таблиц в зависимости от настроек пользователя. Если их не указать, СКД может игнорировать установленные даты, что приведет к неверным остаткам.
Если в отчете требуется группировка по регистратору, ситуация усложняется. Выясним причину: остаток в виртуальной таблице ОстаткиИОбороты без указания периодичности рассчитывается только на начало и конец всего периода. При добавлении поля Регистратор в группировку, СКД не будет знать, какой был остаток после каждого конкретного документа.
Чтобы исправить это, выполним следующие настройки:
ПериодСекунда (или другие поля периодов).ПериодСекунда укажем, что это поле периода с соответствующим типом. Это позволит СКД выстроить хронологическую последовательность движений.Регистратор также установим роль Период (дополнительный).При таком подходе СКД сможет вычислить остаток на каждую «точку» времени, и отчет будет показывать актуальное наличие товара после каждого регистратора.
Иногда объединение через UNION ALL не подходит, например, если один из регистров является основным, а второй — дополняющим. В этом случае эффективно использовать Связи наборов данных на соответствующей закладке конструктора СКД.
Разберем этот метод подробнее:
Склад и Номенклатура.НачалоПериода и КонецПериода. Это гарантирует, что при получении данных для каждой строки номенклатуры подчиненный запрос будет выполняться с правильными границами дат.Этот метод позволяет избежать декартова произведения записей (дублирования строк), которое часто случается при обычных соединениях (JOIN) в запросе, если по одной номенклатуре в разных регистрах разное количество записей за день.
Для успешного построения отчета по двум регистрам с остатками придерживайтесь следующих правил:
Полное соединение в одном запросе по регистратору. Это приведет к геометрическому росту количества строк и искажению итогов.Набор данных - объединение в СКД или ОБЪЕДИНИТЬ ВСЕ в запросе.Регистратор или поля периодов.Следуя этим шагам, мы сможем создать надежный аналитический инструмент, который будет корректно отображать движения и остатки товаров, независимо от сложности структуры исходных данных и количества используемых регистров накопления.