Как корректно объединить и сравнить остатки и обороты из двух разных регистров в одном отчете СКД?

Программист Управленческий учет
← На главную

При разработке сложных отчетов в системе компоновки данных (СКД) часто возникает задача сравнения данных из двух разных регистров накопления. Типичный пример: необходимо сопоставить движения по одной и той же номенклатуре в разных учетных контурах (например, складской учет и производственный учет), чтобы найти расхождения. Основная трудность заключается в том, что при использовании стандартных связей наборов данных документы из одного регистра могут "пропадать" или остатки рассчитываться некорректно. Рассмотрим подробно, как решить эту задачу правильно.

Почему два набора данных — не всегда лучшее решение

Первое, с чем сталкиваются разработчики, — это попытка создать два отдельных набора данных (запроса) и связать их на вкладке Связи наборов данных. Проанализируем ситуацию: связи в СКД работают по принципу левого соединения. Если мы связываем Регистр 1 с Регистром 2 по номенклатуре, то при детализации до регистратора документы из Регистра 2, которых нет в Регистре 1, просто не отобразятся или отобразятся некорректно в иерархии группировок.

Как отмечают опытные специалисты, использование нескольких наборов данных оправдано только в исключительных случаях (например, когда данные берутся из разных баз или принципиально разных источников). Для банальной декомпозиции запроса внутри одной базы лучше использовать один набор данных с оператором ОБЪЕДИНИТЬ ВСЕ. Это дает СКД гораздо больше возможностей для оптимизации и правильного расчета итогов.

Шаг 1. Проектирование запроса через объединение

Рассмотрим правильную структуру запроса. Нам нужно получить данные из двух регистров так, чтобы они находились в разных колонках, но в одной плоской таблице. Для этого мы используем конструкцию ОБЪЕДИНИТЬ ВСЕ, дополняя каждый запрос "пустыми" полями (нулями) для показателей из другого регистра. Проанализируем пример кода:


ВЫБРАТЬ
    СырьеОстаткиИОбороты.Регистратор КАК Регистратор,
    СырьеОстаткиИОбороты.ПериодСекунда КАК ПериодСекунда,
    СырьеОстаткиИОбороты.Номенклатура КАК Номенклатура,
    СырьеОстаткиИОбороты.КоличествоНачальныйОстаток КАК ОстатокНач_Рег1,
    0 КАК ОстатокНач_Рег2,
    СырьеОстаткиИОбороты.КоличествоПриход КАК Приход_Рег1,
    0 КАК Приход_Рег2,
    СырьеОстаткиИОбороты.КоличествоРасход КАК Расход_Рег1,
    0 КАК Расход_Рег2,
    СырьеОстаткиИОбороты.КоличествоКонечныйОстаток КАК ОстатокКон_Рег1,
    0 КАК ОстатокКон_Рег2,
    "Регистр1" КАК ИсточникДанных
ИЗ
    РегистрНакопления.Сырье.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Авто, , ) КАК СырьеОстаткиИОбороты

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ШихтаОстаткиИОбороты.Регистратор,
    ШихтаОстаткиИОбороты.ПериодСекунда,
    ШихтаОстаткиИОбороты.Номенклатура,
    0,
    ШихтаОстаткиИОбороты.КоличествоНачальныйОстаток,
    0,
    ШихтаОстаткиИОбороты.КоличествоПриход,
    0,
    ШихтаОстаткиИОбороты.КоличествоРасход,
    0,
    ШихтаОстаткиИОбороты.КоличествоКонечныйОстаток,
    "Регистр2"
ИЗ
    РегистрНакопления.Шихта.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Авто, , ) КАК ШихтаОстаткиИОбороты

Обратим внимание на важный нюанс: в первом запросе мы задаем псевдонимы колонок (например, ОстатокНач_Рег1), а во втором запросе колонки должны следовать строго в том же порядке. Названия полей во втором запросе не имеют значения — СКД возьмет имена из первого блока.

Шаг 2. Настройка ролей полей (Магия остатков)

Просто объединить запросы недостаточно. Чтобы СКД понимала, как считать остатки на уровнях группировок (например, по Номенклатуре), необходимо правильно настроить Роли полей в схеме компоновки данных. Это критический этап, без которого начальный остаток будет просто суммироваться как обычное число, что приведет к неверным результатам.

Для каждого регистра мы создаем свою "группу остатков". Разберем по шагам:

  1. Для поля ОстатокНач_Рег1 установите роль: Остатки. Имя укажите Группа1, Тип — Начальный. В поле Счетчик укажите соответствующее поле конечного остатка (ОстатокКон_Рег1).
  2. Для поля ОстатокКон_Рег1 установите роль: Остатки. Имя укажите Группа1, Тип — Конечный.
  3. Для полей второго регистра (ОстатокНач_Рег2 и ОстатокКон_Рег2) сделайте то же самое, но используйте другое Имя группы — например, Группа2.

Важно: Если вы укажете одинаковое имя группы для всех полей, СКД попытается "схлопнуть" их в один поток данных, что приведет к ошибкам при выводе документов, существующих только в одном из регистров.

Шаг 3. Использование обязательного измерения-разделителя

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

Решение заключается в добавлении "фиктивного" измерения. В нашем примере кода это поле ИсточникДанных. Выясним, как это работает:

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

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

Шаг 4. Настройка ресурсов и вычисляемых полей

Посмотрим на ситуацию, когда нам нужно вывести разницу между двумя регистрами. Не делайте этого в самом тексте запроса через Приход1 - Приход2, так как это не сработает для остатков. Правильный путь — использование вкладок Вычисляемые поля и Ресурсы.

Создайте вычисляемое поле РазницаПрихода. В выражении ресурсов для него напишите:

СУММА(Приход_Рег1) - СУММА(Приход_Рег2)

Для сравнения остатков используйте аналогичный подход. Помните, что агрегатные функции в ресурсах СКД (СУММА, МАКСИМУМ) корректно обрабатывают роли остатков, если они были настроены на предыдущем шаге.

Шаг 5. Оформление отчета

Для удобства анализа проанализируем настройки Условного оформления. Если ваша задача — найти расхождения, создайте правило:

Это позволит сразу визуально определить номенклатурные позиции, по которым данные в двух регистрах не совпадают, и развернуть их до конкретных регистраторов.

Подведем итог: использование ОБЪЕДИНИТЬ ВСЕ в одном запросе, правильное разделение ролей полей на группы остатков и добавление обязательного фиктивного измерения — это три "кита", на которых строится корректный отчет по сравнению двух регистров в СКД. Такой подход обеспечивает максимальную точность данных и гибкость настройки отчета для конечного пользователя.

← На главную