Отбор компоновки данных из кода: элементы, группы, пользовательские настройки и динамические списки

· 10 мин

Содержание

Чтобы программно установить значение отбора в СКД, добавьте в КомпоновщикНастроек.Настройки.Отбор.Элементы элемент типа ЭлементОтбораКомпоновкиДанных и заполните у него ЛевоеЗначение, ВидСравнения, ПравоеЗначение и Использование = Истина. Если отбор уже есть в настройках отчёта, его не добавляют заново, а находят по полю и меняют правое значение.

Типичная ситуация: бухгалтер открывает «Оборотно-сальдовую ведомость по счёту» из карточки контрагента и ждёт, что отчёт уже отфильтрован по этому контрагенту. Отбор есть в коде, но отчёт показывает всех. Почти всегда причина в пользовательских настройках или в том, что отбор поставили не в тот компоновщик. Ниже код для каждого случая и разбор, почему значение «не доходит» до отчёта.

Где живёт отбор в системе компоновки данных

У отчёта на СКД три слоя, и отбор может оказаться в любом из них:

  • 📐 Схема компоновки (СхемаКомпоновкиДанных) — наборы данных, поля, параметры. Отбора как такового в ней нет, есть только настройки по умолчанию.
  • ⚙️ Настройки (КомпоновщикНастроек.Настройки) — вариант отчёта: структура, отбор, порядок, параметры данных.
  • 👤 Пользовательские настройки (КомпоновщикНастроек.ПользовательскиеНастройки) — то, что пользователь видит в шапке отчёта и в окне «Настройки». Сюда попадают элементы, у которых задан ИдентификаторПользовательскойНастройки.

Отбор бывает на двух уровнях:

ГдеОбъектЧто фильтрует
Весь отчётНастройки.ОтборВсе записи до группировок
Конкретная группировкаНастройки.Структура[0].ОтборТолько записи этой группировки

Коллекция Отбор.Элементы содержит объекты двух типов: ЭлементОтбораКомпоновкиДанных (одно условие) и ГруппаЭлементовОтбораКомпоновкиДанных (условия, связанные через И, ИЛИ, НЕ). При переборе всегда проверяйте тип элемента, иначе обращение к ЛевоеЗначение у группы упадёт с ошибкой.

Способ 1. Изменить значение существующего элемента отбора

Самый частый случай: в варианте отчёта отбор по полю уже заведён (галочка снята), нужно подставить значение и включить его.

&НаСервере
Процедура УстановитьКонтрагентаНаСервере(Контрагент)

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

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

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

Поля сравнивают как объекты: Элемент.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Контрагент"). Сравнение со строкой "Контрагент" всегда даст Ложь.

Способ 2. Добавить элемент в коллекцию ЭлементыОтбора

Когда отбора в варианте нет, его создают методом Добавить(). Удобнее сразу написать универсальную функцию «найти или добавить», чтобы повторный вызов не плодил одинаковые условия:

&НаСервере
Функция УстановитьЭлементОтбораСКД(Отбор, ИмяПоля, Значение,
		ВидСравнения = Неопределено, Использование = Истина)

	Если ВидСравнения = Неопределено Тогда
		ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
	КонецЕсли;

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

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

	Найденный.ВидСравнения   = ВидСравнения;
	Найденный.ПравоеЗначение = Значение;
	Найденный.Использование  = Использование;

	Возврат Найденный;

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

Вызов для склада и для списка организаций:

Отбор = Отчет.КомпоновщикНастроек.Настройки.Отбор;
УстановитьЭлементОтбораСКД(Отбор, "Склад", Склад);

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

Поле через точку

Имя поля можно задавать с разыменованием: "Контрагент.ИНН", "Номенклатура.Родитель". Условие: такое поле должно быть доступно для отбора в схеме. Проверить заранее можно так:

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

Условия через ИЛИ

Группа нужна, когда условие не сводится к одному полю. Пример: документы, где контрагент — заданный ИЛИ сумма больше 100 000:

Группа = Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
Группа.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИли;
Группа.Использование = Истина;

УстановитьЭлементОтбораСКД(Группа, "Контрагент", Контрагент);
УстановитьЭлементОтбораСКД(Группа, "СуммаДокумента", 100000,
	ВидСравненияКомпоновкиДанных.Больше);

Функция работает и с группой, потому что у группы тоже есть коллекция Элементы. Но у группы нет свойства ДоступныеПоляОтбора, поэтому проверку поля делайте по корневому отбору.

Если в конфигурации есть БСП

В типовых конфигурациях на БСП не нужно писать свою функцию. В общем модуле ОбщегоНазначенияКлиентСервер есть процедуры УстановитьЭлементОтбора, ДобавитьЭлементКомпоновки и УстановитьЭлементОтбораДинамическогоСписка. Набор параметров зависит от версии БСП: перед вызовом откройте модуль в конфигураторе и посмотрите описание параметров над процедурой.

Способ 3. Пользовательские настройки и быстрые отборы

Это главная причина вопроса «я установил отбор, а отчёт его не видит». Если у элемента отбора заполнен ИдентификаторПользовательскойНастройки (а для быстрых отборов в шапке отчёта он заполнен всегда), при формировании берётся значение из ПользовательскиеНастройки. Значение в Настройки.Отбор перекрывается.

Порядок действий:

  1. Найдите элемент в Настройки.Отбор, как в способе 1.
  2. Возьмите у него ИдентификаторПользовательскойНастройки.
  3. Если идентификатор не пустой — найдите по нему элемент в пользовательских настройках и меняйте его.
&НаСервере
Процедура УстановитьБыстрыйОтбор(ИмяПоля, Значение)

	Компоновщик = Отчет.КомпоновщикНастроек;
	Поле = Новый ПолеКомпоновкиДанных(ИмяПоля);

	Для Каждого Элемент Из Компоновщик.Настройки.Отбор.Элементы Цикл
		Если ТипЗнч(Элемент) <> Тип("ЭлементОтбораКомпоновкиДанных")
			Или Элемент.ЛевоеЗначение <> Поле Тогда
			Продолжить;
		КонецЕсли;

		Целевой = Элемент;
		Если ЗначениеЗаполнено(Элемент.ИдентификаторПользовательскойНастройки) Тогда
			Пользовательский = Компоновщик.ПользовательскиеНастройки.Элементы.Найти(
				Элемент.ИдентификаторПользовательскойНастройки);
			Если Пользовательский <> Неопределено Тогда
				Целевой = Пользовательский;
			КонецЕсли;
		КонецЕсли;

		Целевой.ПравоеЗначение = Значение;
		Целевой.Использование  = Истина;
		Прервать;
	КонецЦикла;

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

Чтобы добавленный из кода отбор сам появился в шапке отчёта, задайте ему идентификатор и режим отображения:

Элемент.ИдентификаторПользовательскойНастройки = Строка(Новый УникальныйИдентификатор);
Элемент.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.БыстрыйДоступ;

После этого вызовите Компоновщик.ЗагрузитьНастройки(Компоновщик.Настройки), чтобы пользовательские настройки пересобрались, или установите значение уже в них.

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

Способ 4. Изменить схему компоновки на лету

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

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

	СтандартнаяОбработка = Ложь;

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

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

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

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

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

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

Ключевые моменты:

  • 🔑 ПолучитьНастройки() возвращает настройки с уже применёнными пользовательскими. Работайте с этой копией: изменения не испортят вариант, который пользователь видит на экране.
  • 📄 Имя макета берите из свойства отчёта «Основная схема компоновки данных». ОсновнаяСхемаКомпоновкиДанных — имя по умолчанию, в вашем отчёте оно может быть другим.
  • 🧩 Текст запроса набора меняют через Схема.НаборыДанных.НаборДанных1.Запрос (имя набора — как в схеме). Делайте это до вызова КомпоновщикМакета.Выполнить.

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

Отбор по датам и перечислениям: что ломается чаще всего

Даты

Поле Период или Дата в регистрах и документах хранит время. Отбор МеньшеИлиРавно '31.03.2026' отсекает все записи 31 марта после 00:00:00.

УстановитьЭлементОтбораСКД(Отбор, "Дата", НачалоДня(ДатаНачала),
	ВидСравненияКомпоновкиДанных.БольшеИлиРавно);
// второе условие по тому же полю добавляем отдельно,
// иначе функция найдёт первое и перезапишет его
Элемент = Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Элемент.ЛевоеЗначение  = Новый ПолеКомпоновкиДанных("Дата");
Элемент.ВидСравнения   = ВидСравненияКомпоновкиДанных.МеньшеИлиРавно;
Элемент.ПравоеЗначение = КонецДня(ДатаОкончания);
Элемент.Использование  = Истина;

Для периода отчёта правильнее параметры данных, а не отбор. Если параметр в схеме типа СтандартныйПериод, передавайте именно его:

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

Параметр уходит в виртуальные таблицы регистров, а отбор по полю Период фильтрует уже готовый результат и работает медленнее.

Перечисления и предопределённые элементы

  • ❌ ПравоеЗначение = "Поступление" — строка не равна значению перечисления, отбор вернёт пустой отчёт.
  • ✅ На сервере: ПравоеЗначение = Перечисления.ВидыДвиженийНоменклатуры.Поступление (имя перечисления — из вашей конфигурации).
  • ✅ На клиенте менеджер перечислений недоступен, используйте ПредопределенноеЗначение("Перечисление.ВидыДвиженийНоменклатуры.Поступление").

Для иерархических справочников выбирайте вид сравнения осознанно: Равно берёт только сам элемент, ВИерархии — группу со всем содержимым, ВСпискеПоИерархии — несколько групп сразу (правое значение — СписокЗначений).

Отбор в управляемых и обычных формах

Управляемая формаОбычная форма
Объект отбора в спискеСписок.Отбор (элементы СКД)ДокументСписок.Отбор, СправочникСписок.Отбор
Тип вида сравненияВидСравненияКомпоновкиДанныхВидСравнения
Где выполнять кодОтчёт — на сервере (&НаСервере)В модуле формы, контекст один
Передача отбора при открытииПараметр формы Отбор (структура)Свойства формы перед Открыть()

Динамический список

В управляемой форме у динамического списка два места для отбора:

  • 🔒 Список.Отбор — программный отбор. Пользователь его не видит в настройках списка и снять не может. Подходит для жёстких ограничений: «только документы текущей организации».
  • 👤 Список.КомпоновщикНастроек.Настройки.Отбор и пользовательские настройки — то, что пользователь меняет сам через «Ещё → Настроить список».
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	УстановитьЭлементОтбораСКД(Список.Отбор, "Организация", Параметры.Организация);
КонецПроцедуры

Если условие должно попасть прямо в текст запроса списка (например, в параметр виртуальной таблицы остатков), используйте параметр: Список.Параметры.УстановитьЗначениеПараметра("Склад", Склад). Параметр устанавливайте в ПриСозданииНаСервере, до первого вывода списка.

Открытие отчёта с отбором

Самый простой способ из другой формы — передать структуру в параметре Отбор:

ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Отбор", Новый Структура("Контрагент", Контрагент));
ПараметрыФормы.Вставить("СформироватьПриОткрытии", Истина);
ОткрытьФорму("Отчет.ОстаткиПоКонтрагенту.Форма", ПараметрыФормы);

Ключ структуры — имя поля отчёта. Платформа сама найдёт или создаст элемент отбора с видом сравнения Равно.

Обычные формы

В обычных формах отбор списка — объект Отбор со своими элементами по именам реквизитов: Отбор.Контрагент.Установить(Контрагент) или поштучно Значение, ВидСравнения, Использование. Перечисление видов сравнения здесь ВидСравнения, а не ВидСравненияКомпоновкиДанных. Отчёт на СКД в обычной форме работает с тем же КомпоновщикНастроек, что и в управляемой, поэтому код способов 1–4 переносится без изменений.

Продвинутые приёмы: отбор в виртуальных таблицах и отключение условий

Виртуальные таблицы регистров

При включённом автозаполнении схемы компоновщик сам переносит условие отбора в параметр Условие виртуальной таблицы, если поле есть среди её измерений. Отбор по Номенклатура для Остатки регистра накопления сработает до вычисления остатков, это быстро.

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

Временно выключить отбор

Удалять элемент не нужно, достаточно Элемент.Использование = Ложь. Это сохраняет его настройку для следующего формирования.

Если всё же надо удалить несколько элементов, идите по коллекции с конца:

Элементы = Отбор.Элементы;
Для Сч = 1 По Элементы.Количество() Цикл
	Элемент = Элементы[Элементы.Количество() - Сч];
	Если ТипЗнч(Элемент) = Тип("ЭлементОтбораКомпоновкиДанных")
		И Элемент.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Склад") Тогда
		Элементы.Удалить(Элемент);
	КонецЕсли;
КонецЦикла;

Прямой цикл с удалением пропускает соседние элементы: после удаления индексы сдвигаются.

Отбор на группировке

Чтобы ограничить только одну таблицу или группировку, а не весь отчёт, работайте с её отбором: Настройки.Структура[0].Отбор. Индекс считайте по структуре варианта: 0 — первый элемент верхнего уровня в окне настроек.

Почему отбор не применяется: разбор по симптомам

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

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

Чем отбор отличается от параметра данных?
Параметр подставляется в запрос до выполнения и может попасть в виртуальную таблицу. Отбор накладывается как условие на поля набора. Для периода и среза остатков используйте параметр, для фильтра по реквизитам — отбор.
Можно ли передать в ВСписке массив, а не список значений?
Надёжнее преобразовать массив в СписокЗначений через ЗагрузитьЗначения. Так отбор корректно отобразится и в пользовательских настройках.
Как отобрать незаполненные значения?
Вид сравнения НеЗаполнено, правое значение не задаётся. Он ловит и пустую ссылку, и NULL из левого соединения.
Почему отбор работает в конфигураторе, а у пользователя нет?
У пользователя сохранён свой вариант или свои пользовательские настройки отчёта. Проверьте код на пользователе со сброшенными настройками и учтите способ 3.
Где менять отбор в отчёте типовой конфигурации, не снимая её с поддержки?
В расширении конфигурации: перехватите обработчик модуля отчёта или формы и вызовите свой код установки отбора. Расширения доступны с платформы 8.3.6.