Почему в СКД некорректно считаются ресурсы и как исправить задвоение сумм при соединениях

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

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

Анализ проблемы: почему данные «размножаются»

Рассмотрим ситуацию, описанную в обращении. Автор использует виртуальную таблицу ВзаиморасчетыСКонтрагентамиПоДокументамРасчетов.ОстаткиИОбороты и присоединяет к ней несколько регистров сведений, таких как ПараметрыПродажАгентов, КонтактнаяИнформация и другие. Основная проблема — задвоение сумм — возникает в момент выполнения ЛЕВОЕ СОЕДИНЕНИЕ.

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

Посмотрим на фрагмент исходного запроса, вызывающий подозрение:


ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПараметрыПродажАгентов КАК ПараметрыПродажАгентов
ПО ВзаиморасчетыСКонтрагентамиПоДокументамРасчетовОстаткиИОбороты.ДокументРасчетовСКонтрагентом.ТорговыйПредставитель = ПараметрыПродажАгентов.Агент
И ВзаиморасчетыСКонтрагентамиПоДокументамРасчетовОстаткиИОбороты.Период <= ПараметрыПродажАгентов.Период

В данном случае условие <= по периоду практически гарантирует, что на одну дату документа из регистра накопления система найдет множество записей в регистре сведений за все последующие даты. Это классическая причина «раздувания» выборки.

Решение 1: Использование среза последних

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

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

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


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

Как подтвердил автор темы, использование среза последних помогло устранить дублирование строк и привело суммы в порядок.

Решение 2: Периодичность виртуальных таблиц

Проанализируем поведение виртуальной таблицы ОстаткиИОбороты. У нее есть важный параметр — Периодичность. Рассмотрим два варианта:

  1. Регистратор: система выдает детальные записи по каждому документу, который сделал движения. Это необходимо для детальных отчетов, но именно здесь чаще всего проявляются ошибки соединений.
  2. Период (День, Месяц и т.д.): данные агрегируются за указанный интервал.

Если при смене периодичности с «Регистратор» на «Период» суммы остатков выровнялись, но «поломались» обороты (приход/расход), это сигнализирует о том, что в ресурсах СКД неправильно настроены Роли полей. Выясним, как это исправить.

Решение 3: Правильная настройка ролей остатков

В СКД недостаточно просто поставить галочку в колонке «Ресурс». Для полей остатков необходимо на закладке «Наборы данных» в колонке Роль указать специфические настройки:

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

Решение 4: Суммирование «Суммы документа»

Особый случай — поле СуммаДокумента. Если документ попал в несколько строк отчета (например, из-за разных номенклатурных позиций или аналитик), его общая сумма будет суммироваться многократно. Чтобы в итогах по документу или контрагенту сумма документа отображалась корректно (без учета дублей), можно использовать следующее выражение в ресурсах:


Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(СуммаДокумента)", "ДокументРасчетовСКонтрагентом"))

Это выражение сначала определит максимальную (единственную) сумму для каждого уникального документа, а затем сложит эти значения в итогах вышестоящей группировки.

Проблема последней секунды

Часто обороты считаются неверно, если не учитывать границы времени. При передаче параметров в виртуальную таблицу убедимся, что &КонецПериода включает последнюю секунду дня. В коде 1С это решается использованием объекта Граница, а внутри СКД — стандартной функцией КОНЕЦПЕРИОДА(&КонецПериода, "ДЕНЬ").

Проанализируем типичный пример установки параметров:


// В настройках СКД для параметров лучше использовать:
&КонецПериода = КонецПериода(&КонецПериода, "ДЕНЬ")

Резюме и рекомендации

Подведем итог нашему исследованию. Если ваш отчет «врет» в цифрах, выполните следующие шаги:

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

Соблюдение этих правил позволит вам создавать надежные и точные отчеты, которые будут корректно отображать как текущие остатки, так и обороты за произвольный период.

← На главную