Почему в отчете СКД неверно рассчитываются остатки при соединении таблиц и как это исправить

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

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

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

Анализ проблемы и исходного запроса

Посмотрим на пример запроса, в котором к виртуальной таблице ОстаткиИОбороты присоединяется справочник сотрудников для получения реквизита ВидЗанятости:


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

Выясним, почему при таком подходе остатки начинают искажаться при группировках вроде «Регистратор» или «Организация» без вывода физлица:

  1. Размножение строк из-за связи «один ко многим»: Одно физическое лицо может иметь несколько элементов в справочнике сотрудников (например, основное место работы и внутреннее совместительство, либо увольнение и повторный прием). Даже конструкция ВЫБРАТЬ РАЗЛИЧНЫЕ вернет несколько строк для одного физлица, если у него различаются виды занятости. В результате левого соединения строки виртуальной таблицы дублируются, а СКД суммирует остатки по каждой задвоенной строке.
  2. Особенности перестроения запросов СКД: Когда из группировок отчета исключаются ключевые измерения регистра (например, Физлицо), СКД оптимизирует запрос и выполняет расчет остатков уже после наложения соединения. Если кардинальность набора данных нарушена, механизм автоматического расчета остатков платформы 1С дает сбой.

Способ 1. Разделение запроса на два набора данных через связи СКД (рекомендуемый)

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

Разберем по шагам настройку схемы компоновки данных:

  1. Набор данных 1 (Запрос с остатками): Создаем набор данных — запрос, выбирающий данные только из виртуальной таблицы регистра накопления без каких-либо соединений со сторонними таблицами.
    
    ВЫБРАТЬ
        Взаиморасчеты.Физлицо КАК Физлицо,
        Взаиморасчеты.Физлицо.Пол КАК Пол,
        Взаиморасчеты.Организация КАК Организация,
        Взаиморасчеты.Регистратор КАК Регистратор,
        Взаиморасчеты.ПериодСекунда КАК ПериодСекунда,
        Взаиморасчеты.СуммаВзаиморасчетовНачальныйОстаток КАК СуммаВзаиморасчетовНачальныйОстаток,
        Взаиморасчеты.СуммаВзаиморасчетовКонечныйОстаток КАК СуммаВзаиморасчетовКонечныйОстаток,
        Взаиморасчеты.СуммаВзаиморасчетовОборот КАК СуммаВзаиморасчетовОборот,
        Взаиморасчеты.СуммаВзаиморасчетовПриход КАК СуммаВзаиморасчетовПриход,
        Взаиморасчеты.СуммаВзаиморасчетовРасход КАК СуммаВзаиморасчетовРасход
    ИЗ
        РегистрНакопления.ВзаиморасчетыСРаботникамиОрганизаций.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Авто, , ) КАК Взаиморасчеты
    
  2. Набор данных 2 (Запрос с дополнительными реквизитами): Создаем отдельный набор данных, выбирающий свойства сотрудников.
    
    ВЫБРАТЬ
        Сотрудники.Физлицо КАК Физлицо,
        Сотрудники.ВидЗанятости КАК ВидЗанятости
    ИЗ
        Справочник.СотрудникиОрганизаций КАК Сотрудники
    
  3. Настройка связей наборов данных: Переходим на вкладку Связи наборов данных и добавляем строку связи:
    • Источник связи: НаборДанных1
    • Приемник связи: НаборДанных2
    • Условие связи: Физлицо = Физлицо

При таком подходе СКД сначала рассчитывает все начальные, конечные остатки и обороты по исходным правилам регистра накопления, а затем подтягивает значение поля ВидЗанятости на этапе компоновки результата. Это полностью исключает искажение числовых ресурсов при любых комбинациях группировок.

Способ 2. Корректная настройка ролей полей и родительских измерений

Если требуется оставить один набор данных, необходимо строго настроить роли полей на вкладке Наборы данных:

  1. Для измерений регистра (Организация, Физлицо) в колонке Роль обязательно должен быть установлен флаг Измерение.
  2. Для поля ВидЗанятости в окне редактирования роли необходимо указать в свойстве Родительское поле измерение Физлицо. Это указывает СКД, что данное поле является зависимым реквизитом измерения, а не самостоятельным измерением, формирующим остатки.
  3. Для временных полей необходимо правильно настроить иерархию периодов: для поля ПериодСекунда указать роль «Период, 1», а для поля Регистратор — роль «Период, 2» с указанием родительского поля периода при необходимости.

Способ 3. Обеспечение однозначности соответствия 1:1 в подзапросе

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


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

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

← На главную