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

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

При разработке отчетов в Системе компоновки данных (СКД) на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью вывода агрегированных показателей, таких как количество определенных видов документов (например, копий и оригиналов дипломов или аттестатов). Ситуация существенно осложняется, когда данные выбираются из нескольких табличных частей одного документа (например, «Подача заявлений» и «Документы для поступления» в анкете абитуриента). В таких случаях возникает две проблемы: ошибка группировки в запросе (связанная с некорректным использованием секции СГРУППИРОВАТЬ ПО) и задвоение (перемножение) строк при левом соединении табличных частей.

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

Выясняем причину проблемы: Декартово произведение табличных частей

Проанализируем типичный запрос, который часто пытаются написать начинающие разработчики. В документе АнкетаАбитуриента есть две табличные части:

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

Если мы попытаемся соединить эти табличные части простым левым соединением по полю Ссылка (самому документу), СУБД выполнит так называемое декартово произведение строк для каждого документа. Это означает, что для одной анкеты система вернет нам 3 * 2 = 6 строк в результирующей выборке. Любые агрегатные функции, такие как СУММА(ВЫБОР КОГДА...), будут рассчитываться по этим размноженным строкам, из-за чего количество оригиналов и копий будет завышено в несколько раз. Попытки наложить костыли вида НомерСтроки = 1 не решают проблему системно и приводят к потере данных, если документов или заявлений больше одного.

Рассмотрим четыре правильных способа решения этой задачи.

Решение №1. Предварительная группировка во временных таблицах (Рекомендуемый способ для одного запроса)

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

Разберем этот алгоритм по шагам:

  1. Выбираем данные из табличной части документов, проверяем условия (например, что это документ об образовании) и рассчитываем количество копий и оригиналов с помощью агрегатной функции СУММА.
  2. Группируем результат по полю Ссылка (анкета) и помещаем во временную таблицу ВТ_ИтогиПоДокументам.
  3. В основном запросе выбираем данные из табличной части заявлений и левым соединением подключаем нашу временную таблицу.

Посмотрим на пример реализации такого запроса:


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

СГРУППИРОВАТЬ ПО
    АнкетаДокументы.Ссылка
;

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

При таком подходе СУБД сначала рассчитает точное количество документов для каждого физического лица, а затем сопоставит его со строками специальностей. Задвоение результатов полностью исключено.

Решение №2. Использование нескольких наборов данных в СКД (Best Practice)

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

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

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

Этот способ является наиболее производительным и архитектурно правильным в экосистеме 1С, так как платформа берет на себя оптимизацию запросов к СУБД, гарантируя отсутствие дублей строк.

Решение №3. Использование вычисляемых полей и ресурсов СКД

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

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

  1. Переходим на вкладку «Вычисляемые поля».
  2. Добавляем новое поле с именем ЭтоКопия. В колонке «Выражение» пишем формулу:
    Выбор Когда ВидДокумента = "Копия" Тогда 1 Иначе 0 Конец
  3. Добавляем второе поле ЭтоОригинал с выражением:
    Выбор Когда ВидДокумента = "Оригинал" Тогда 1 Иначе 0 Конец
  4. Переходим на вкладку «Ресурсы».
  5. Переносим поля ЭтоКопия и ЭтоОригинал в список ресурсов. В качестве выражения для расчета итогов указываем стандартную агрегатную функцию Сумма(ЭтоКопия) и Сумма(ЭтоОригинал) соответственно.

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

Решение №4. Создание пользовательских полей в режиме «1С:Предприятие»

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

Для этого выполним следующие действия:

  1. Откроем настройки отчета и перейдем в раздел «Пользовательские поля».
  2. Добавим «Новое поле-выражение».
  3. В поле «Выражение детальных записей» (определяет расчет для каждой отдельной строки отчета) введем логическое выражение:
    Выбор Когда [Вид предоставленного документа] = "Копия" Тогда 1 Иначе 0 Конец
  4. В поле «Выражение итоговых записей» (определяет, как система будет аккумулировать эти значения в группировках и общих итогах) обязательно оборачиваем выражение в агрегатную функцию суммы:
    Сумма(Выбор Когда [Вид предоставленного документа] = "Копия" Тогда 1 Иначе 0 Конец)

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

Применение любого из предложенных подходов гарантирует корректный расчет итогов, предотвращает возникновение ошибок СУБД и значительно ускоряет работу сформированных отчетов.

← На главную