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