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

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

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

Исходный запрос разработчика выглядит следующим образом:


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

В результате, если в документе на 20 USD содержится две товарные позиции, сумма взаиморасчетов по документу превращается в 40 USD. Выясним причину такого поведения и разберем способы решения проблемы.

Причина задвоения данных

Проанализируем ситуацию: регистр ВзаиморасчетыСКонтрагентами не хранит данные в разрезе номенклатуры — в нем сумма фиксируется на весь документ-регистратор (или договор/заказ). В свою очередь, регистр Продажи содержит детализацию по каждой строке номенклатуры.

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

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

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

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

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

Способ 2. Корректная настройка выражений ресурсов в СКД

Если требуется оставить один запрос с соединением, стандартное указание функции Сумма(СумаОборот) приведет к ошибкам. Простое использование Максимум(СумаОборот) решит проблему только для строки регистратора, но сломает итоги по контрагенту и общий итог по отчету.

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

  1. Добавим поле СумаОборот в список ресурсов.
  2. Для группировки по документу укажем выражение: Максимум(СумаОборот) В колонке Рассчитывать по... выберем только Регистратор.
  3. Для вышестоящих уровней (группировка Контрагент и Общий итог) добавим отдельную строку ресурса с выражением:
    
    Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(СумаОборот)", "Регистратор"))
    
    В колонке Рассчитывать по... укажем Контрагент и ОбщиеИтоги.
  4. Для детальных записей или группировки Номенклатура ресурс рассчитывать не нужно (оставляем поле пустым или задаем 0), чтобы не вводить пользователей в заблуждение суммой документа напротив каждой товарной позиции.

Способ 3. Сворачивание номенклатуры в строку (функция «СоединитьСтроки»)

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

Разберем по шагам данный подход:

  1. В запросе исключаем номенклатуру из группировок, выбирая только данные взаиморасчетов.
  2. Номенклатуру получаем отдельным подчиненным набором или добавляем как вычисляемое поле.
  3. В ресурсах для поля Номенклатура указываем выражение: СоединитьСтроки(Массив(Номенклатура), ", ")

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

← На главную