Установка отборов программно — одна из самых востребованных задач при разработке в 1С:Предприятие 8.3. Без грамотной фильтрации данных невозможно построить эффективные отчеты, динамические списки или управляемые формы. Однако многие разработчики сталкиваются с проблемами: отбор либо не применяется, либо работает некорректно, либо «съедает» производительность при больших объемах данных.
В этой статье мы разберем 5 проверенных способов программной установки отборов — от базовых методов для начинающих до оптимизированных решений для работы с большими массивами. Каждый метод сопровождается реальными примерами кода, которые можно сразу использовать в своих конфигурациях. Особое внимание уделим типичным ошибкам (например, почему отбор через Запрос.Текст может игнорироваться) и способам их обхода.
Материал будет полезен как новичкам, которые только осваивают встроенный язык 1С, так и опытным программистам, ищущим оптимальные решения для сложных задач. Все примеры актуальны для платформы 1С:Предприятие 8.3 (включая последние релизы 2026 года) и совместимы с большинством типовых конфигураций (Бухгалтерия 3.0, УТ 11, ЗУП 3.1 и др.).
1. Установка отбора через свойство объекта (простой способ)
Самый очевидный и универсальный метод — использование свойства Отбор у объектов, которые его поддерживают (например, ДокументОбъект.Список, СправочникОбъект.Список или ДинамическийСписок). Этот способ подходит для большинства типовых задач, где не требуется сложная логика фильтрации.
Преимущества метода:
- 🔹 Простота реализации — достаточно 1-2 строк кода.
- 🔹 Визуальная наглядность: отборы отображаются в интерфейсе пользователя (если объект поддерживает управляемые формы).
- 🔹 Автоматическая оптимизация — платформа сама выбирает оптимальный способ применения фильтра (индексы, кэширование и т.д.).
Пример установки отбора для списка документов РеализацияТоваровУслуг по дате и контрагенту:
Документы = Документы.РеализацияТоваровУслуг.СоздатьМенеджерВыбора();
Документы.Отбор.Дата.Установить(НачалоДня(ТекущаяДата()), КонецДня(ТекущаяДата()));
Документы.Отбор.Контрагент.Установить(Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка"));
Выборка = Документы.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Номер);
КонецЦикла;
⚠️ Внимание: Если вы устанавливаете отбор дляДинамическогоСпискав управляемой форме, не забудьте вызвать методПрименитьОтбор()илиОбновить(), иначе изменения не отобразятся в интерфейсе.
Для справочников синтаксис аналогичен, но можно использовать дополнительные параметры, например, отбор по иерархии:
Справочник = Справочники.Номенклатура.СоздатьМенеджерВыбора();
Справочник.Отбор.Родитель.Установить(Справочники.Номенклатура.ПустаяСсылка()); // Только элементы верхнего уровня
Справочник.Отбор.ЭтоГруппа.Установить(Ложь); // Исключаем группы
Если вам нужно сбросить все отборы для объекта, используйте метод ОчиститьОтбор() без параметров. Это полезно при динамическом изменении фильтров в форме.
2. Отбор в запросах: когда и как использовать
Запросы — мощный инструмент для работы с данными в 1С, и установка отбора непосредственно в тексте запроса часто дает выигрыш в производительности. Однако здесь есть нюансы: неправильно составленный отбор может привести к полному сканированию таблиц вместо использования индексов.
Основные правила для отборов в запросах:
- 📌 Используйте параметры запроса (
Параметры.Добавить()) вместо жесткого прописывания значений — это защищает от SQL-инъекций и упрощает поддержку кода. - 📌 Для дат всегда применяйте функции
НАЧАЛОПЕРИОДА()илиКОНЕЦПЕРИОДА(), чтобы избежать проблем с временем. - 📌 Сложные условия (с
ИЛИ) лучше выносить в отдельные секцииГДЕс круглыми скобками для явного указания приоритета.
Пример оптимизированного запроса с отбором по нескольким полям:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Ссылка КАК Ссылка,
| РеализацияТоваровУслуг.Дата КАК Дата,
| РеализацияТоваровУслуг.СуммаДокумента КАК Сумма
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
| РеализацияТоваровУслуг.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И РеализацияТоваровУслуг.Контрагент В (&СписокКонтрагентов)
| И РеализацияТоваровУслуг.ПометкаУдаления = ЛОЖЬ";
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ТекущаяДата() - 30));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ТекущаяДата()));
Запрос.УстановитьПараметр("СписокКонтрагентов", МассивКонтрагентов); // Массив ссылок
Результат = Запрос.Выполнить();
Для динамического формирования условия ГДЕ можно использовать конструктор запросов:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ | ......"; // Базовая часть
Условие = Новый Структура("Тип, Значение", "Даты", "РеализацияТоваровУслуг.Дата МЕЖДУ &Начало И &Конец");
Если НЕ ПустаяДата(ДатаНачала) Тогда
Запрос.Текст = Запрос.Текст + " |ГДЕ " + Условие.Значение;
Запрос.УстановитьПараметр("Начало", НачалоДня(ДатаНачала));
Запрос.УстановитьПараметр("Конец", КонецДня(ДатаКонца));
КонецЕсли;
3. Динамические списки: отборы с привязкой к форме
Динамические списки (ДинамическийСписок) — ключевой элемент управляемых форм в 1С 8.3. Они позволяют гибко настраивать отображение данных с учетом прав пользователя и текущего контекста. Отборы здесь можно устанавливать как программно, так и через настройки формы.
Особенности работы с отборами в динамических списках:
- 🔄 Отборы применяются на сервере, что снижает нагрузку на клиент.
- 🔄 Поддерживается иерархическая фильтрация (например, для справочников с группами).
- 🔄 Можно комбинировать с
ОтборПоумолчаниюиз свойств формы.
Пример программной установки отбора для динамического списка в форме документа:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Отбор = Новый Структура;
Отбор.Вставить("Дата", Новый ЗначениеВДиапазоне(НачалоДня(ТекущаяДата()), КонецДня(ТекущаяДата())));
Отбор.Вставить("Контрагент", Справочники.Контрагенты.ТекущийЭлемент());
ЭлементыФормы.СписокДокументов.Отбор = Отбор;
ЭлементыФормы.СписокДокументов.ПрименитьОтбор();
КонецПроцедуры
Для сложных сценариев (например, когда отбор зависит от других элементов формы) используйте обработчик ПередЗагрузкойДанных:
&НаСервере
Процедура СписокДокументовПередЗагрузкойДанных(Элемент, ПараметрыЗагрузки)
Если ЭлементыФормы.ФильтрПоДате.Значение Тогда
ПараметрыЗагрузки.Отбор.Дата = Новый ЗначениеВДиапазоне(
ЭлементыФормы.ДатаНачала.Значение,
ЭлементыФормы.ДатаОкончания.Значение
);
КонецЕсли;
КонецПроцедуры
⚠️ Внимание: Если динамический список привязан к регистру сведений или регистру накопления, отбор по измерениям может существенно влиять на производительность. В таких случаях проверяйте план запроса через ОбъяснитьЗапрос().
Убедиться, что отбор установлен на сервере|Проверить вызов ПрименитьОтбор() после изменения|Тестировать с разными правами пользователей|Оптимизировать отборы для больших объемов данных-->
4. Отборы в отчетах и система компоновки данных (СКД)
Система компоновки данных (СКД) предоставляет гибкие инструменты для установки отборов, включая:
- 📊 Статические отборы (задаются в схеме компоновки).
- 📊 Динамические отборы (устанавливаются программно).
- 📊 Пользовательские настройки (сохраняются между сеансами).
Для программной установки отбора в СКД используйте свойство Настройки.Отбор:
Отчет = Отчеты.Продажи.Создать();
СхемаКомпоновки = Отчет.КомпоновщикНастроек.ПолучитьНастройкиПоУмолчанию();
ОтборЭлемент = СхемаКомпоновки.Отбор.Элементы.Добавить(Тип("ОтборКомпоновкиДанныхЭлемент"));
ОтборЭлемент.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Дата");
ОтборЭлемент.ВидСравнения = ВидСравненияКомпоновкиДанных.БольшеИлиРавно;
ОтборЭлемент.ПравоеЗначение = НачалоДня(ТекущаяДата() - 30);
Отчет.КомпоновщикНастроек.ЗагрузитьНастройки(СхемаКомпоновки);
Отчет.СкомпоноватьРезультат();
Для работы с пользовательскими настройками (например, сохраненными вариантами отчета) используйте метод ЗагрузитьПользовательскиеНастройки():
Настройки = Отчет.КомпоновщикНастроек.ПолучитьНастройки();
Отчет.КомпоновщикНастроек.ЗагрузитьПользовательскиеНастройки(Настройки, ИмяПользователя, ИмяВарианта);
Отбор = Настройки.Отбор.Элементы.Найти(Новый ПолеКомпоновкиДанных("Контрагент"));
Если Отбор <> Неопределено Тогда
Отбор.ПравоеЗначение = Справочники.Контрагенты.ТекущийЭлемент();
КонецЕсли;
Если отчет использует параметры, их можно привязать к отборам через свойство ПараметрыКомпоновкиДанных:
Параметр = СхемаКомпоновки.ПараметрыДанных.Элементы.Добавить(Тип("ПараметрКомпоновкиДанныхЭлемент"));
Параметр.Имя = "Период";
Параметр.Значение = Новый Структура("Начало, Конец", НачалоМесяца(ТекущаяДата()), КонецМесяца(ТекущаяДата()));
ОтборЭлемент.ПравоеЗначение = Новый ПолеКомпоновкиДанных("Параметр.Период.Начало");
5. Оптимизация отборов для больших баз данных
При работе с большими объемами данных (десятки тысяч записей и более) неоптимальные отборы могут приводить к «зависанию» системы. Рассмотрим ключевые приемы оптимизации:
| Проблема | Решение | Пример кода |
|---|---|---|
| Полное сканирование таблиц | Использовать индексированные поля в отборе | Отбор.Дата = ТекущаяДата() (поле Дата должно быть индексировано) |
Сложные условия с ИЛИ |
Разбивать на несколько запросов с ОБЪЕДИНИТЬ |
|
| Отбор по неиндексированному полю | Добавить поле в индекс или использовать временные таблицы | |
Для анализа производительности используйте метод ОбъяснитьЗапрос():
Запрос = Новый Запрос("ВЫБРАТЬ ... ГДЕ ...");
Объяснение = Запрос.ОбъяснитьЗапрос();
Сообщить(Объяснение.Текст); // Показывает план выполнения
Если запрос выполняется слишком долго, рассмотрите альтернативные подходы:
- 🔧 Виртуальные таблицы — для работы с регистрами накопления.
- 🔧 Объектные выборки — если нужно получить только ссылки на объекты.
- 🔧 Пакетные запросы — для обработки данных порциями.
Как ускорить отбор по неиндексированному полю?
Если поле не входит в индекс, но отбор по нему критичен, можно:
1. Добавить поле в индекс (если это возможно по логике данных).
2. Использовать временную таблицу с предварительной выборкой:
ВТ = Новый ВременнаяТаблица;
Запрос = Новый Запрос("ВЫГРУЗИТЬ ВТ ИЗ ВЫБРАТЬ РазрезыПоследних.Ссылка, РазрезыПоследних.НеиндексПоле ИЗ РегистрСведений.РазрезыПоследних КАК РазрезыПоследних");
Запрос.Выполнить();
3. Применить отбор уже к временной таблице.
6. Типичные ошибки и как их избежать
Даже опытные разработчики иногда допускают ошибки при работе с отборами. Рассмотрим самые распространенные:
- Отбор не применяется.
Причина: забыли вызвать
ПрименитьОтбор()для динамического списка или не обновили форму.Решение: всегда проверяйте, что после установки отбора вызывается метод обновления.
- Некорректная работа с датами.
Причина: не учтено время (например, отбор по
Дата = ТекущаяДата()может не включать документы с временем 00:00:01).Решение: используйте
НачалоДня()/КонецДня()или диапазоны. - Ошибки при работе с NULL.
Причина: отбор по полю со значением
NULL(например,Контрагент = NULL) работает не так, как ожидается.Решение: используйте
ЗначениеЗаполнено()илиЕСТЬ NULLв запросах.
Пример корректной работы с NULL:
// Неправильно (не вернет записи с пустым контрагентом):
Отбор.Контрагент.Установить(Неопределено);
// Правильно:
Отбор.Контрагент.Установить(Справочники.Контрагенты.ПустаяСсылка());
// В запросе:
ГДЕ Контрагент ЕСТЬ NULL
Еще одна типичная проблема — конфликт отборов, когда несколько условий противоречат друг другу. Например:
Отбор.Дата.Установить(НачалоДня(ТекущаяДата()), КонецДня(ТекущаяДата()));
Отбор.Дата.Установить(НачалоМесяца(ТекущаяДата())); // Перезапишет предыдущий отбор!
Чтобы избежать таких ситуаций, используйте ДобавитьУсловиеОтбора() для динамических списков или объединяйте условия в запросе через И:
ГДЕ
Дата МЕЖДУ &Начало И &Конец
И Контрагент = &Контрагент
Всегда проверяйте результат отбора на тестовых данных, особенно если условия фильтрации зависят от пользовательского ввода или динамических параметров.
FAQ: Частые вопросы по программной установке отборов
Как установить отбор по нескольким значениям одного поля (например, список контрагентов)?
Для отбора по нескольким значениям используйте:
- В запросах: оператор
В (&МассивЗначений). - В динамических списках:
Отбор.Поле.Установить(МассивЗначений).
Пример для запроса:
Запрос.Текст = "ВЫБРАТЬ ... ГДЕ Контрагент В (&СписокКонтрагентов)";
Запрос.УстановитьПараметр("СписокКонтрагентов", МассивКонтрагентов);
Можно ли установить отбор по полю, которого нет в основной таблице (например, по реквизиту табличной части)?
Да, но нужно использовать вложенные запросы или соединения таблиц.
Пример для табличной части документа:
ВЫБРАТЬ
РеализацияТоваровУслуг.Ссылка
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
СУЩЕСТВУЕТ (
ВЫБРАТЬ РАЗЛИЧНЫЕ 1
ИЗ Документ.РеализацияТоваровУслуг.Товары КАК Товары
ГДЕ Товары.Ссылка = РеализацияТоваровУслуг.Ссылка
И Товары.Номенклатура = &Номенклатура
)
Почему отбор в динамическом списке не работает после обновления платформы?
В новых версиях 1С:Предприятие 8.3 (начиная с 8.3.20+) изменился механизм применения отборов для некоторых объектов. Проверьте:
- Вызывается ли
ПрименитьОтбор()после установки всех условий. - Не конфликтуют ли программные отборы с настройками формы (проверьте свойство
ОтборПоумолчанию). - Обновлены ли метаданные конфигурации (иногда требуется пересоздать динамический список).
Если проблема сохраняется, используйте Обновить() для принудительного пересчета:
ЭлементыФормы.СписокДокументов.Отбор.Очистить();
ЭлементыФормы.СписокДокументов.ПрименитьОтбор();
ЭлементыФормы.СписокДокументов.Обновить();
Как сделать отбор по иерархическому справочнику (включая подчиненные элементы)?
Для иерархических справочников используйте функцию ПолучитьСсылкиПотомков() или оператор ПОДЧИНЕНО в запросах.
Пример для программного отбора:
Родитель = Справочники.Номенклатура.НайтиПоНаименованию("Товары");
СписокПотомков = Родитель.ПолучитьСсылкиПотомков();
Отбор = Новый Структура("Поле", СписокПотомков);
ЭлементыФормы.СписокНоменклатуры.Отбор.Ссылка = Отбор;
В запросе:
ГДЕ Номенклатура ПОДЧИНЕНО &Родитель
Можно ли сохранить пользовательские отборы между сеансами?
Да, для этого используйте:
- Для динамических списков: свойство
ПользовательскиеНастройкиформы. - Для отчетов СКД: метод
СохранитьПользовательскиеНастройки().
Пример сохранения отбора в форме:
&НаКлиенте
Процедура СохранитьНастройки(Команда)
Настройки = ЭлементыФормы.СписокДокументов.ПолучитьНастройки();
ПользовательскиеНастройки.СохранитьНастройки(Настройки, ИмяПользователя);
КонецПроцедуры