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