Как передать в параметр схемы компоновки несколько значений сразу
Содержание
Чтобы передать в параметр СКД список значений, откройте схему компоновки на вкладке Параметры, задайте параметру тип и установите флаг Доступен список значений. В тексте запроса используйте условие ГДЕ Таблица.Поле В (&ИмяПараметра), а из кода передавайте объект СписокЗначений через ПараметрыДанных.УстановитьЗначениеПараметра().
Это работает одинаково во всех конфигурациях на платформе 8.3: механизм принадлежит платформе, а не БП, ЗУП или УТ. Проблемы почти всегда возникают в трёх местах: не стоит флаг списка, список пустой или значение из кода затирается пользовательскими настройками. Каждое из них разобрано ниже, с кодом.
Как настроить параметр СКД под список значений
Параметр в схеме появляется автоматически, как только вы пишете &ИмяПараметра в тексте запроса набора данных. Но платформа создаёт его как одиночный. Для списка нужно поправить настройки вручную.
- Откройте отчёт в Конфигураторе и дважды щёлкните макет
ОсновнаяСхемаКомпоновкиДанных. - Перейдите на вкладку
Параметры. - Найдите строку параметра, например
СписокСкладов. - В колонке
Типвыберите конкретный тип:СправочникСсылка.Склады. Не оставляйте тип пустым. - Установите флаг в колонке
Доступен список значений. - При необходимости заполните колонку
Значение— это значение по умолчанию.
Что дают остальные колонки:
| Колонка | Зачем нужна для списка |
|---|---|
Тип | Определяет, из какого справочника или перечисления пользователь выбирает элементы |
Доступен список значений | Разрешает несколько значений вместо одного |
Доступные значения | Ограничивает выбор фиксированным набором (удобно для перечислений) |
Ограничение доступности | Прячет параметр от пользователя: значение задаёт только код |
Выражение | Вычисляет значение параметра из других параметров |
Включать в доступные поля | Позволяет вывести значение параметра в отчёт как поле |
Если тип не задан, при выборе значений пользователь сначала увидит окно выбора типа. Это неудобно и провоцирует ошибки: в список попадают ссылки на чужие справочники.
Для перечислений и коротких фиксированных наборов заполните колонку Доступные значения. Например, для параметра с типом перечисления можно оставить только три значения из двадцати. Пользователь отметит галочками нужные, а лишние варианты не увидит вовсе.
Чтобы параметр был виден в шапке отчёта, в настройках варианта на вкладке Параметры поставьте ему признак включения в пользовательские настройки. Тогда пользователь отметит нужные склады прямо на форме отчёта, без открытия настроек.
Условие В (&Параметр) в запросе набора данных
Сам текст запроса для списка почти не отличается от обычного. Вместо знака равенства пишут оператор В:
ВЫБРАТЬ
ТоварыНаСкладахОстатки.Склад КАК Склад,
ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
ТоварыНаСкладахОстатки.КоличествоОстаток КАК Количество
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(
,
Склад В (&СписокСкладов)) КАК ТоварыНаСкладахОстатки
Имя регистра здесь условное: подставьте регистр своей конфигурации. Смысл в другом — условие стоит в параметрах виртуальной таблицы. Так отбор накладывается до расчёта остатков, а не после.
Варианты записи условия под разные задачи:
- 📌
Поле В (&Список)— точное совпадение с одним из элементов. - 🌳
Поле В ИЕРАРХИИ (&Список)— элемент или любой вложенный в выбранные группы. Пригодится, когда пользователь отмечает группы номенклатуры. - 🚫
НЕ Поле В (&Список)— всё, кроме перечисленного.
Оператор В принимает и СписокЗначений, и Массив. Для параметра СКД, у которого стоит флаг списка, штатное значение — СписокЗначений: именно его создаёт форма выбора на экране отчёта.
Пустой список: почему отчёт ничего не выводит
Главная ловушка. Условие Склад В (&СписокСкладов) с пустым списком не означает «без отбора». Оно означает «склад равен одному из нуля значений», то есть ни одной строки. Пользователь снимает все галочки — и получает пустой отчёт.
Есть три рабочих способа это обойти.
Способ 1. Фигурные скобки СКД
В запросах СКД можно описать необязательное условие в фигурных скобках:
ВЫБРАТЬ
Продажи.Номенклатура,
Продажи.Сумма
ИЗ
РегистрНакопления.Продажи КАК Продажи
{ГДЕ
Продажи.Номенклатура В (&СписокНоменклатуры)}
Если параметр не используется (флажок у него в настройках снят), компоновка выбрасывает условие из итогового запроса. Отбора нет, выводится всё.
Способ 2. Флаг-параметр
Добавьте булев параметр и проверяйте его прямо в условии:
ГДЕ
(НЕ &ОтборПоСкладам
ИЛИ Остатки.Склад В (&СписокСкладов))
Значение ОтборПоСкладам выставляйте из кода по количеству элементов списка или выводите на форму отдельной галочкой. Этот способ прозрачнее: читая запрос, сразу видно логику.
Способ 3. Отключать параметр из кода
Перед формированием проверьте список и снимите использование:
Параметр = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(
Новый ПараметрКомпоновкиДанных("СписокСкладов"));
Если Параметр <> Неопределено Тогда
Параметр.Использование = (Список.Количество() > 0);
КонецЕсли;
Работает в паре со способом 1: параметр выключен — условие в скобках исчезло.
| Способ | Когда подходит | Риск |
|---|---|---|
| Фигурные скобки | Условие относится к основной таблице запроса | Нельзя поставить скобки внутрь параметров виртуальной таблицы |
| Флаг-параметр | Нужна явная логика, условие внутри вложенного запроса | Лишний параметр в настройках |
| Отключение из кода | Отчёт формируется программно | Пользователь в интерфейсе по-прежнему может получить пустой список |
Передача списка значений из кода в схему компоновки
Программно параметр заполняют, когда отчёт формируется без формы: в обработке, регламентном задании, печатной форме. Ниже полный пример — от макета до таблицы значений с результатом.
Функция ОстаткиПоСкладам(МассивСкладов) Экспорт
СписокСкладов = Новый СписокЗначений;
СписокСкладов.ЗагрузитьЗначения(МассивСкладов);
СхемаКомпоновки = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Компоновщик = Новый КомпоновщикНастроекКомпоновкиДанных;
Компоновщик.Инициализировать(
Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКомпоновки));
Компоновщик.ЗагрузитьНастройки(СхемаКомпоновки.НастройкиПоУмолчанию);
Компоновщик.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра(
"СписокСкладов", СписокСкладов);
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки,
Компоновщик.ПолучитьНастройки(), , ,
Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
Процессор = Новый ПроцессорКомпоновкиДанных;
Процессор.Инициализировать(МакетКомпоновки);
Результат = Новый ТаблицаЗначений;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(Результат);
ПроцессорВывода.Вывести(Процессор);
Возврат Результат;
КонецФункции
Что здесь важно:
- 🔹
ЗагрузитьЗначения()превращает массив в список одной строкой, без цикла. - 🔹
УстановитьЗначениеПараметра()сам включает использование параметра. Отдельно ставитьИспользование = Истинане нужно. - 🔹 Функция с
ПолучитьМакет()выполняется на сервере: поместите её в модуль объекта отчёта или в серверную процедуру формы.
Если отчёт открыт на форме
В типовом отчёте с формой у пользователя есть свои настройки, и они накладываются поверх варианта. Если вы заполнили параметр в Настройки, а пользователь сохранил другое значение, победит пользовательское.
Надёжное место для подстановки — обработчик ПриКомпоновкеРезультата в модуле объекта отчёта:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра(
"СписокСкладов", ПолучитьСкладыТекущегоПользователя());
СтандартнаяОбработка = Ложь;
ДокументРезультат.Очистить();
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных,
Настройки, ДанныеРасшифровки);
Процессор = Новый ПроцессорКомпоновкиДанных;
Процессор.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(Процессор);
КонецПроцедуры
ПолучитьНастройки() возвращает уже объединённые настройки: вариант плюс пользовательские. Параметр, заданный после этого вызова, ничто не перезапишет. Функцию ПолучитьСкладыТекущегоПользователя() напишите под свою задачу — она должна вернуть СписокЗначений.
Если параметр заполняет только код, поставьте ему в схеме флаг Ограничение доступности. Иначе пользователь увидит его в настройках и удивится, почему его выбор игнорируется.
Отбор «В списке» вместо параметра
Иногда параметр вовсе не нужен. Если поле есть среди доступных полей отчёта, список можно передать через отбор:
ЭлементОтбора = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Склад");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
ЭлементОтбора.ПравоеЗначение = СписокСкладов;
ЭлементОтбора.Использование = Истина;
Разница с параметром: отбор компоновка подставляет туда, куда считает нужным, обычно в конец запроса. Параметр вы ставите сами — например, внутрь виртуальной таблицы остатков, где он работает быстрее и даёт правильные остатки по выбранным складам.
Составные типы и вычисляемые значения параметра
Параметр может хранить ссылки разных типов. Задача типовая: отчёт по расчётам, где контрагентом бывает и Контрагенты, и ФизическиеЛица.
Как настроить:
- В колонке
Типпараметра включите флагСоставной тип данных. - Отметьте все нужные типы ссылок.
- Установите
Доступен список значений.
В список можно положить элементы обоих справочников вперемешку. Условие Расчеты.Контрагент В (&СписокКонтрагентов) сравнит каждую ссылку с элементами её типа — приводить типы вручную не нужно.
Список = Новый СписокЗначений;
Список.Добавить(Справочники.Контрагенты.НайтиПоКоду("000000012"));
Список.Добавить(Справочники.ФизическиеЛица.НайтиПоКоду("000000045"));
Если в список из кода попадёт Неопределено или пустая ссылка, отбор её примет как обычное значение. Перед передачей удаляйте такие элементы, иначе в отчёт попадут строки с незаполненным полем.
Колонка «Выражение»
В колонке Выражение параметра пишут выражение на языке СКД. Его вычисляет компоновка, а не код. Значение из выражения подставляется, когда пользователь не задал параметр сам.
Выражения СКД вычисляются с ограничениями: не каждый метод встроенного языка в них доступен, а методы объектов вроде списка значений лучше в них не вызывать. Если выражение выдаёт ошибку при формировании, вычислите значение в коде и передайте готовым параметром — это надёжнее.
Колонка Выражение хорошо подходит для простых вещей: дата конца периода из даты начала, булев флаг из другого параметра, значение по умолчанию из константы через функцию общего модуля, разрешённую для вызова из СКД.
Большие списки: когда оператор В начинает тормозить
Условие В (&Список) платформа превращает в запрос к СУБД с перечислением значений. На десятках и сотнях элементов это незаметно. Когда в список попадают тысячи ссылок, страдает план запроса, а отчёт формируется заметно дольше.
Что делать:
- 🎯 Отбирайте по признаку, а не по перечню. Нужна номенклатура одного вида — передайте вид, а не все 5 000 карточек этого вида:
Номенклатура.ВидНоменклатуры В (&Виды). - 🌳 Используйте группы. Вместо всех элементов группы передайте саму группу и
В ИЕРАРХИИ. - 🗂️ Вынесите отбор во временную таблицу. СКД поддерживает пакетные запросы с
ПОМЕСТИТЬ. Сначала отберите ссылки во временную таблицу по условию, затем соедините её с основной выборкой. - 📍 Ставьте условие в параметры виртуальной таблицы, а не в
ГДЕпосле неё. Остатки и обороты тогда считаются только по нужным разрезам.
Пример с временной таблицей в наборе данных СКД:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_Товары
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Ссылка В ИЕРАРХИИ (&ГруппыТоваров)
ИНДЕКСИРОВАТЬ ПО
Ссылка
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Продажи.Номенклатура,
Продажи.Сумма
ИЗ
РегистрНакопления.Продажи КАК Продажи
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Товары КАК ВТ_Товары
ПО Продажи.Номенклатура = ВТ_Товары.Ссылка
Пользователь выбирает 3 группы, а не 3 000 товаров. Запрос к СУБД получает короткий список и соединение по индексу.
Как увидеть итоговый запрос
Когда непонятно, попало ли условие в запрос, посмотрите, что компоновка собрала на самом деле. После вызова КомпоновщикМакета.Выполнить() текст запроса лежит в макете:
ТекстЗапроса = МакетКомпоновки.НаборыДанных.НаборДанных1.Запрос;
НаборДанных1 — имя набора данных из вашей схемы. Поставьте точку останова на этой строке и сравните текст при пустом и заполненном списке. Сразу видно, выбросила ли компоновка условие в фигурных скобках и куда она поставила отбор «В списке».
Ошибки при передаче списка в параметр СКД
Эти симптомы встречаются чаще всего. Сопоставьте свой случай с описанием.