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