Как устранить задвоение сумм в отчете СКД при соединении таблиц?

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

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

Почему происходит задвоение сумм? Проанализируем ситуацию

Разберем классический пример из практики. Автор темы столкнулся с тем, что суммы в его отчете повторяются до 7 раз. Посмотрим на фрагмент его запроса:


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

Выясним причину проблемы: виртуальная таблица ОстаткиИОбороты с периодичностью «День» выдает одну строку на каждую дату, где были движения. Однако в физической таблице регистра ВалютаКонтроль за этот же день может быть 5, 10 или 100 записей (движений). Когда мы выполняем ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN) по полю Период, СУБД сопоставляет одну строку из левой таблицы со всеми подходящими строками из правой.

В результате, если в день было 7 операций, одна строка с остатком превратится в 7 идентичных строк в выборке. Когда СКД начнет рассчитывать ресурсы (например, СУММА(СуммаКонечныйОстаток)), она просто сложит эти 7 одинаковых значений. Именно так получается «магическое» умножение остатка на количество движений.

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

Самый правильный архитектурный подход в 1С — это использование механизмов самой системы компоновки вместо «сырых» соединений в тексте запроса. Давайте рассмотрим, как это сделать по шагам:

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

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

Метод 2. Исправление условий соединения и типизации периодов

Если вы все же решили использовать один запрос, проанализируем ошибку в соединении периодов. В виртуальной таблице ОстаткиИОбороты при детализации «День» поле Период — это всегда 00:00:00 (начало дня). В физической же таблице Период — это точное время документа.

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

Чтобы соединение было корректным, необходимо привести периоды к одному виду:


ПО ВалютаОстаткиИОбороты.Период = НАЧАЛОПЕРИОДА(ВалютаКонтроль.Период, ДЕНЬ)
И ВалютаОстаткиИОбороты.Организация = ВалютаКонтроль.Организация
// И другие измерения...

Важно: Всегда соединяйте таблицы по максимально полному набору измерений (Организация, Склад, Номенклатура и т.д.). Соединение только по периоду — это прямой путь к получению «каши» из данных разных контрагентов в одной строке.

Метод 3. Агрегация во вложенном запросе

Рассмотрим ситуацию, когда нам нужно подтянуть из второй таблицы какое-то одно значение (например, дату последней операции или номер документа), но при этом нельзя допустить размножения строк. В этом случае правую таблицу нужно предварительно «схлопнуть» во вложенном запросе.

Пример структуры запроса:


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

Используя группировку (СГРУППИРОВАТЬ ПО) во вложенном запросе, мы гарантируем, что на одну дату из таблицы остатков придется ровно одна строка из таблицы контроля. Суммы остатков останутся в сохранности.

Метод 4. Роли полей в СКД

Посмотрим на настройки набора данных в конструкторе СКД. У каждого поля есть колонка «Роль». Для полей остатков крайне важно правильно настроить параметры:

Почему «ВЫБРАТЬ РАЗЛИЧНЫЕ» не является решением?

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

Подведем итоги

Чтобы ваш отчет в СКД не «врал» в итоговых суммах, придерживайтесь следующих правил:

  1. Приоритет связям наборов данных: Если нужно соединить остатки с движениями — делайте это через закладку «Связи наборов данных» в СКД, а не внутри одного SQL-запроса.
  2. Контроль измерений: Соединяйте таблицы по всем ключевым полям (измерениям), а не только по дате.
  3. Группировка: Если соединение в запросе неизбежно, предварительно группируйте присоединяемую таблицу до одной строки на ключ связи.
  4. Проверка периодов: Всегда помните о разнице между началом дня в виртуальных таблицах и точным временем в физических таблицах.

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

← На главную