Как передать в параметр схемы компоновки несколько значений сразу

· 9 мин

Содержание

Чтобы передать в параметр СКД список значений, откройте схему компоновки на вкладке Параметры, задайте параметру тип и установите флаг Доступен список значений. В тексте запроса используйте условие ГДЕ Таблица.Поле В (&ИмяПараметра), а из кода передавайте объект СписокЗначений через ПараметрыДанных.УстановитьЗначениеПараметра().

Это работает одинаково во всех конфигурациях на платформе 8.3: механизм принадлежит платформе, а не БП, ЗУП или УТ. Проблемы почти всегда возникают в трёх местах: не стоит флаг списка, список пустой или значение из кода затирается пользовательскими настройками. Каждое из них разобрано ниже, с кодом.

Как настроить параметр СКД под список значений

Параметр в схеме появляется автоматически, как только вы пишете &ИмяПараметра в тексте запроса набора данных. Но платформа создаёт его как одиночный. Для списка нужно поправить настройки вручную.

  1. Откройте отчёт в Конфигураторе и дважды щёлкните макет ОсновнаяСхемаКомпоновкиДанных.
  2. Перейдите на вкладку Параметры.
  3. Найдите строку параметра, например СписокСкладов.
  4. В колонке Тип выберите конкретный тип: СправочникСсылка.Склады. Не оставляйте тип пустым.
  5. Установите флаг в колонке Доступен список значений.
  6. При необходимости заполните колонку Значение — это значение по умолчанию.

Что дают остальные колонки:

КолонкаЗачем нужна для списка
ТипОпределяет, из какого справочника или перечисления пользователь выбирает элементы
Доступен список значенийРазрешает несколько значений вместо одного
Доступные значенияОграничивает выбор фиксированным набором (удобно для перечислений)
Ограничение доступностиПрячет параметр от пользователя: значение задаёт только код
ВыражениеВычисляет значение параметра из других параметров
Включать в доступные поляПозволяет вывести значение параметра в отчёт как поле

Если тип не задан, при выборе значений пользователь сначала увидит окно выбора типа. Это неудобно и провоцирует ошибки: в список попадают ссылки на чужие справочники.

Для перечислений и коротких фиксированных наборов заполните колонку Доступные значения. Например, для параметра с типом перечисления можно оставить только три значения из двадцати. Пользователь отметит галочками нужные, а лишние варианты не увидит вовсе.

Чтобы параметр был виден в шапке отчёта, в настройках варианта на вкладке Параметры поставьте ему признак включения в пользовательские настройки. Тогда пользователь отметит нужные склады прямо на форме отчёта, без открытия настроек.

Условие В (&Параметр) в запросе набора данных

Сам текст запроса для списка почти не отличается от обычного. Вместо знака равенства пишут оператор В:

ВЫБРАТЬ
	ТоварыНаСкладахОстатки.Склад КАК Склад,
	ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
	ТоварыНаСкладахОстатки.КоличествоОстаток КАК Количество
ИЗ
	РегистрНакопления.ТоварыНаСкладах.Остатки(
			,
			Склад В (&СписокСкладов)) КАК ТоварыНаСкладахОстатки

Имя регистра здесь условное: подставьте регистр своей конфигурации. Смысл в другом — условие стоит в параметрах виртуальной таблицы. Так отбор накладывается до расчёта остатков, а не после.

Варианты записи условия под разные задачи:

  • 📌 Поле В (&Список) — точное совпадение с одним из элементов.
  • 🌳 Поле В ИЕРАРХИИ (&Список) — элемент или любой вложенный в выбранные группы. Пригодится, когда пользователь отмечает группы номенклатуры.
  • 🚫 НЕ Поле В (&Список) — всё, кроме перечисленного.

Оператор В принимает и СписокЗначений, и Массив. Для параметра СКД, у которого стоит флаг списка, штатное значение — СписокЗначений: именно его создаёт форма выбора на экране отчёта.

Пустой список: почему отчёт ничего не выводит

Главная ловушка. Условие Склад В (&СписокСкладов) с пустым списком не означает «без отбора». Оно означает «склад равен одному из нуля значений», то есть ни одной строки. Пользователь снимает все галочки — и получает пустой отчёт.

Есть три рабочих способа это обойти.

Способ 1. Фигурные скобки СКД

В запросах СКД можно описать необязательное условие в фигурных скобках:

ВЫБРАТЬ
	Продажи.Номенклатура,
	Продажи.Сумма
ИЗ
	РегистрНакопления.Продажи КАК Продажи
{ГДЕ
	Продажи.Номенклатура В (&СписокНоменклатуры)}

Если параметр не используется (флажок у него в настройках снят), компоновка выбрасывает условие из итогового запроса. Отбора нет, выводится всё.

Способ 2. Флаг-параметр

Добавьте булев параметр и проверяйте его прямо в условии:

ГДЕ
	(НЕ &ОтборПоСкладам
		ИЛИ Остатки.Склад В (&СписокСкладов))

Значение ОтборПоСкладам выставляйте из кода по количеству элементов списка или выводите на форму отдельной галочкой. Этот способ прозрачнее: читая запрос, сразу видно логику.

Способ 3. Отключать параметр из кода

Перед формированием проверьте список и снимите использование:

Параметр = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(
	Новый ПараметрКомпоновкиДанных("СписокСкладов"));
Если Параметр <> Неопределено Тогда
	Параметр.Использование = (Список.Количество() > 0);
КонецЕсли;

Работает в паре со способом 1: параметр выключен — условие в скобках исчезло.

СпособКогда подходитРиск
Фигурные скобкиУсловие относится к основной таблице запросаНельзя поставить скобки внутрь параметров виртуальной таблицы
Флаг-параметрНужна явная логика, условие внутри вложенного запросаЛишний параметр в настройках
Отключение из кодаОтчёт формируется программноПользователь в интерфейсе по-прежнему может получить пустой список

Передача списка значений из кода в схему компоновки

Программно параметр заполняют, когда отчёт формируется без формы: в обработке, регламентном задании, печатной форме. Ниже полный пример — от макета до таблицы значений с результатом.

Функция ОстаткиПоСкладам(МассивСкладов) Экспорт

	СписокСкладов = Новый СписокЗначений;
	СписокСкладов.ЗагрузитьЗначения(МассивСкладов);

	СхемаКомпоновки = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");

	Компоновщик = Новый КомпоновщикНастроекКомпоновкиДанных;
	Компоновщик.Инициализировать(
		Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКомпоновки));
	Компоновщик.ЗагрузитьНастройки(СхемаКомпоновки.НастройкиПоУмолчанию);

	Компоновщик.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра(
		"СписокСкладов", СписокСкладов);

	КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
	МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки,
		Компоновщик.ПолучитьНастройки(), , ,
		Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));

	Процессор = Новый ПроцессорКомпоновкиДанных;
	Процессор.Инициализировать(МакетКомпоновки);

	Результат = Новый ТаблицаЗначений;
	ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
	ПроцессорВывода.УстановитьОбъект(Результат);
	ПроцессорВывода.Вывести(Процессор);

	Возврат Результат;

КонецФункции

Что здесь важно:

  • 🔹 ЗагрузитьЗначения() превращает массив в список одной строкой, без цикла.
  • 🔹 УстановитьЗначениеПараметра() сам включает использование параметра. Отдельно ставить Использование = Истина не нужно.
  • 🔹 Функция с ПолучитьМакет() выполняется на сервере: поместите её в модуль объекта отчёта или в серверную процедуру формы.

Если отчёт открыт на форме

В типовом отчёте с формой у пользователя есть свои настройки, и они накладываются поверх варианта. Если вы заполнили параметр в Настройки, а пользователь сохранил другое значение, победит пользовательское.

Надёжное место для подстановки — обработчик ПриКомпоновкеРезультата в модуле объекта отчёта:

Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)

	Настройки = КомпоновщикНастроек.ПолучитьНастройки();
	Настройки.ПараметрыДанных.УстановитьЗначениеПараметра(
		"СписокСкладов", ПолучитьСкладыТекущегоПользователя());

	СтандартнаяОбработка = Ложь;
	ДокументРезультат.Очистить();

	КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
	МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных,
		Настройки, ДанныеРасшифровки);

	Процессор = Новый ПроцессорКомпоновкиДанных;
	Процессор.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);

	ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
	ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
	ПроцессорВывода.Вывести(Процессор);

КонецПроцедуры

ПолучитьНастройки() возвращает уже объединённые настройки: вариант плюс пользовательские. Параметр, заданный после этого вызова, ничто не перезапишет. Функцию ПолучитьСкладыТекущегоПользователя() напишите под свою задачу — она должна вернуть СписокЗначений.

Если параметр заполняет только код, поставьте ему в схеме флаг Ограничение доступности. Иначе пользователь увидит его в настройках и удивится, почему его выбор игнорируется.

Отбор «В списке» вместо параметра

Иногда параметр вовсе не нужен. Если поле есть среди доступных полей отчёта, список можно передать через отбор:

ЭлементОтбора = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение  = Новый ПолеКомпоновкиДанных("Склад");
ЭлементОтбора.ВидСравнения   = ВидСравненияКомпоновкиДанных.ВСписке;
ЭлементОтбора.ПравоеЗначение = СписокСкладов;
ЭлементОтбора.Использование  = Истина;

Разница с параметром: отбор компоновка подставляет туда, куда считает нужным, обычно в конец запроса. Параметр вы ставите сами — например, внутрь виртуальной таблицы остатков, где он работает быстрее и даёт правильные остатки по выбранным складам.

Составные типы и вычисляемые значения параметра

Параметр может хранить ссылки разных типов. Задача типовая: отчёт по расчётам, где контрагентом бывает и Контрагенты, и ФизическиеЛица.

Как настроить:

  1. В колонке Тип параметра включите флаг Составной тип данных.
  2. Отметьте все нужные типы ссылок.
  3. Установите Доступен список значений.

В список можно положить элементы обоих справочников вперемешку. Условие Расчеты.Контрагент В (&СписокКонтрагентов) сравнит каждую ссылку с элементами её типа — приводить типы вручную не нужно.

Список = Новый СписокЗначений;
Список.Добавить(Справочники.Контрагенты.НайтиПоКоду("000000012"));
Список.Добавить(Справочники.ФизическиеЛица.НайтиПоКоду("000000045"));

Если в список из кода попадёт Неопределено или пустая ссылка, отбор её примет как обычное значение. Перед передачей удаляйте такие элементы, иначе в отчёт попадут строки с незаполненным полем.

Колонка «Выражение»

В колонке Выражение параметра пишут выражение на языке СКД. Его вычисляет компоновка, а не код. Значение из выражения подставляется, когда пользователь не задал параметр сам.

Выражения СКД вычисляются с ограничениями: не каждый метод встроенного языка в них доступен, а методы объектов вроде списка значений лучше в них не вызывать. Если выражение выдаёт ошибку при формировании, вычислите значение в коде и передайте готовым параметром — это надёжнее.

Колонка Выражение хорошо подходит для простых вещей: дата конца периода из даты начала, булев флаг из другого параметра, значение по умолчанию из константы через функцию общего модуля, разрешённую для вызова из СКД.

Большие списки: когда оператор В начинает тормозить

Условие В (&Список) платформа превращает в запрос к СУБД с перечислением значений. На десятках и сотнях элементов это незаметно. Когда в список попадают тысячи ссылок, страдает план запроса, а отчёт формируется заметно дольше.

Что делать:

  • 🎯 Отбирайте по признаку, а не по перечню. Нужна номенклатура одного вида — передайте вид, а не все 5 000 карточек этого вида: Номенклатура.ВидНоменклатуры В (&Виды).
  • 🌳 Используйте группы. Вместо всех элементов группы передайте саму группу и В ИЕРАРХИИ.
  • 🗂️ Вынесите отбор во временную таблицу. СКД поддерживает пакетные запросы с ПОМЕСТИТЬ. Сначала отберите ссылки во временную таблицу по условию, затем соедините её с основной выборкой.
  • 📍 Ставьте условие в параметры виртуальной таблицы, а не в ГДЕ после неё. Остатки и обороты тогда считаются только по нужным разрезам.

Пример с временной таблицей в наборе данных СКД:

ВЫБРАТЬ
	Номенклатура.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_Товары
ИЗ
	Справочник.Номенклатура КАК Номенклатура
ГДЕ
	Номенклатура.Ссылка В ИЕРАРХИИ (&ГруппыТоваров)

ИНДЕКСИРОВАТЬ ПО
	Ссылка
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	Продажи.Номенклатура,
	Продажи.Сумма
ИЗ
	РегистрНакопления.Продажи КАК Продажи
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Товары КАК ВТ_Товары
		ПО Продажи.Номенклатура = ВТ_Товары.Ссылка

Пользователь выбирает 3 группы, а не 3 000 товаров. Запрос к СУБД получает короткий список и соединение по индексу.

Как увидеть итоговый запрос

Когда непонятно, попало ли условие в запрос, посмотрите, что компоновка собрала на самом деле. После вызова КомпоновщикМакета.Выполнить() текст запроса лежит в макете:

ТекстЗапроса = МакетКомпоновки.НаборыДанных.НаборДанных1.Запрос;

НаборДанных1 — имя набора данных из вашей схемы. Поставьте точку останова на этой строке и сравните текст при пустом и заполненном списке. Сразу видно, выбросила ли компоновка условие в фигурных скобках и куда она поставила отбор «В списке».

Ошибки при передаче списка в параметр СКД

Эти симптомы встречаются чаще всего. Сопоставьте свой случай с описанием.

Диагностика: выберите симптом

Частые вопросы

Можно ли передать в параметр СКД массив вместо списка значений?
Запрос оператор В примет и массив. Но форма отчёта и сохранённые настройки работают со списком значений, поэтому надёжнее передавать СписокЗначений — массив превращается в него методом ЗагрузитьЗначения().
Как вывести в шапку отчёта выбранные значения параметра?
Включите у параметра флаг «Включать в доступные поля» — он появится среди полей отчёта, и его можно вывести в заголовок. Второй вариант — включить вывод параметров данных в настройках вывода варианта.
Чем В ИЕРАРХИИ отличается от В для списка с группами?
Оператор В сравнивает ссылку с самой группой и вложенные элементы не находит. В ИЕРАРХИИ берёт группу и всё её содержимое на любой глубине.
Где хранится значение параметра между запусками отчёта?
В пользовательских настройках отчёта, если параметр в них включён. Пользователь может сохранить разные наборы значений как варианты или настройки.
Нужно ли указывать тип у параметра, если значение задаётся только из кода?
Желательно. Тип помогает компоновке правильно построить условие и избавляет от путаницы, если параметр однажды выведут на форму.