При разработке отчетов в Системе компоновки данных (СКД) на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью вывода агрегированных показателей, таких как количество определенных видов документов (например, копий и оригиналов дипломов или аттестатов). Ситуация существенно осложняется, когда данные выбираются из нескольких табличных частей одного документа (например, «Подача заявлений» и «Документы для поступления» в анкете абитуриента). В таких случаях возникает две проблемы: ошибка группировки в запросе (связанная с некорректным использованием секции СГРУППИРОВАТЬ ПО) и задвоение (перемножение) строк при левом соединении табличных частей.
В этой статье мы подробно разберем причины возникновения этих ошибок и рассмотрим несколько профессиональных архитектурных решений, которые позволят получить абсолютно точные данные в отчете без падения производительности системы.
Проанализируем типичный запрос, который часто пытаются написать начинающие разработчики. В документе АнкетаАбитуриента есть две табличные части:
ПодачаЗаявлений — список специальностей, на которые абитуриент подает заявления (например, 3 специальности).ДокументыДляПоступления — список предоставленных документов, где указано, копия это или оригинал (например, 2 документа: паспорт и аттестат).Если мы попытаемся соединить эти табличные части простым левым соединением по полю Ссылка (самому документу), СУБД выполнит так называемое декартово произведение строк для каждого документа. Это означает, что для одной анкеты система вернет нам 3 * 2 = 6 строк в результирующей выборке. Любые агрегатные функции, такие как СУММА(ВЫБОР КОГДА...), будут рассчитываться по этим размноженным строкам, из-за чего количество оригиналов и копий будет завышено в несколько раз. Попытки наложить костыли вида НомерСтроки = 1 не решают проблему системно и приводят к потере данных, если документов или заявлений больше одного.
Рассмотрим четыре правильных способа решения этой задачи.
Если нам необходимо построить отчет на основе одного запроса (например, для последующей выгрузки данных), лучшим решением будет вынесение подсчета документов в отдельную временную таблицу с предварительной группировкой. Таким образом, мы соединяем с табличной частью заявлений уже свернутые данные, где на одну анкету приходится строго одна строка с посчитанными итогами.
Разберем этот алгоритм по шагам:
СУММА.Ссылка (анкета) и помещаем во временную таблицу ВТ_ИтогиПоДокументам.Посмотрим на пример реализации такого запроса:
ВЫБРАТЬ
АнкетаДокументы.Ссылка КАК Анкета,
СУММА(ВЫБОР
КОГДА АнкетаДокументы.ПредоставленаКопия = ИСТИНА
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ) КАК КоличествоКопий,
СУММА(ВЫБОР
КОГДА АнкетаДокументы.ПредоставленаКопия = ЛОЖЬ
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ) КАК КоличествоОригиналов
ПОМЕСТИТЬ ВТ_ИтогиПоДокументам
ИЗ
Документ.АнкетаАбитуриента.ДокументыДляПоступления КАК АнкетаДокументы
ГДЕ
АнкетаДокументы.ДокументДляПоступления.ДокументОПолученномОбразовании = ИСТИНА
СГРУППИРОВАТЬ ПО
АнкетаДокументы.Ссылка
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
АнкетаЗаявки.Ссылка.ФизЛицо КАК ФизЛицо,
АнкетаЗаявки.Ссылка.ДатаРождения КАК ДатаРождения,
АнкетаЗаявки.ПрограммаОбучения КАК ПрограммаОбучения,
ЕСТЬNULL(ИтогиДокументов.КоличествоКопий, 0) КАК КоличествоКопий,
ЕСТЬNULL(ИтогиДокументов.КоличествоОригиналов, 0) КАК КоличествоОригиналов
ИЗ
Документ.АнкетаАбитуриента.ПодачаЗаявлений КАК АнкетаЗаявки
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ИтогиПоДокументам КАК ИтогиДокументов
ПО АнкетаЗаявки.Ссылка = ИтогиДокументов.Анкета
При таком подходе СУБД сначала рассчитает точное количество документов для каждого физического лица, а затем сопоставит его со строками специальностей. Задвоение результатов полностью исключено.
Механизм компоновки данных 1С спроектирован так, чтобы избавить разработчика от написания сложных запросов с соединениями. Мы можем распределить выборку по разным наборам данных, а СКД сама объединит их на уровне процессора компоновки.
Для реализации этого метода выполним следующие действия в конструкторе схемы компоновки данных:
ПодачаЗаявлений.ДокументыДляПоступления.НаборДанных1, приемником — НаборДанных2, а в качестве условия соединения свяжем поля Ссылка (или Анкета) обоих наборов.Этот способ является наиболее производительным и архитектурно правильным в экосистеме 1С, так как платформа берет на себя оптимизацию запросов к СУБД, гарантируя отсутствие дублей строк.
Если в схеме компоновки данных у нас уже есть поле, определяющее статус документа (например, строковое поле ВидДокумента, принимающее значения "Копия" или "Оригинал"), мы можем настроить подсчет итогов без изменения исходного запроса. Для этого используются механизмы вычисляемых полей и ресурсов.
Рассмотрим подробнее настройку схемы компоновки в конфигураторе:
ЭтоКопия. В колонке «Выражение» пишем формулу:
Выбор Когда ВидДокумента = "Копия" Тогда 1 Иначе 0 Конец
ЭтоОригинал с выражением:
Выбор Когда ВидДокумента = "Оригинал" Тогда 1 Иначе 0 Конец
ЭтоКопия и ЭтоОригинал в список ресурсов. В качестве выражения для расчета итогов указываем стандартную агрегатную функцию Сумма(ЭтоКопия) и Сумма(ЭтоОригинал) соответственно.Теперь СКД автоматически подсчитает суммы по всем группировкам отчета и выведет корректные общие итоги, не требуя от нас прописывать математическую логику внутри тяжелых секций СГРУППИРОВАТЬ ПО в СУБД.
Иногда отчет уже находится у конечного пользователя, и у нас нет возможности или прав для изменения конфигурации или схемы компоновки в конфигураторе. В таком случае задачу можно решить непосредственно в пользовательском режиме (режиме предприятия) через настройку варианта отчета.
Для этого выполним следующие действия:
Выбор Когда [Вид предоставленного документа] = "Копия" Тогда 1 Иначе 0 Конец
Сумма(Выбор Когда [Вид предоставленного документа] = "Копия" Тогда 1 Иначе 0 Конец)
Важное примечание: Обратите внимание на использование квадратных скобок [ ] вокруг имени поля. В синтаксисе СКД для пользовательских выражений квадратные скобки указывают системе на то, что внутри содержится имя другого доступного поля отчета (в нашем примере — пользовательского поля отбора Вид предоставленного документа).
Применение любого из предложенных подходов гарантирует корректный расчет итогов, предотвращает возникновение ошибок СУБД и значительно ускоряет работу сформированных отчетов.