Работа с системой компоновки данных (СКД) в 1С:Предприятие часто требует динамической настройки отборов — например, при формировании отчётов с изменяемыми параметрами или интеграции с внешними системами. Вручную прописывать условия в конструкторе не всегда удобно, особенно когда значения зависят от логики программы или действий пользователя. В этой статье разберём, как программно установить значение отбора в СКД на встроенном языке, включая нюансы для разных версий платформы и типичные ошибки, которые портят результат.
Основная сложность заключается в том, что структура СКД не всегда очевидна: отборы могут быть вложенными, использовать сложные условия или ссылаться на виртуальные таблицы. Мы рассмотрим пять проверенных способов — от простого задания значения через свойство Значение до работы с коллекцией ЭлементыОтбора и динамического изменения схемы компоновки. Особое внимание уделим различиям между управляемыми и обычными формами, а также тому, как избежать ошибок при работе с датами и перечислениями.
1. Базовые понятия: что такое отбор в СКД и где он хранится
Отбор в системе компоновки данных — это набор условий, которые фильтруют данные перед их выводом в отчёт. В отличие от обычных запросов, где условия пишутся напрямую в тексте, в СКД отборы хранятся в объекте настроек компоновки (НастройкиКомпоновкиДанных) и могут динамически изменяться.
Физически отборы представлены в двух местах:
- 📁 Схема компоновки данных — здесь определяются доступные поля для отбора (в разделе
Настройки → Отборконструктора СКД). - 🔧 Настройки пользователя — здесь хранятся текущие значения отборов, которые можно менять программно.
Важно понимать, что 1С:Предприятие 8.3 работает с отборами через коллекцию ЭлементыОтбора, где каждый элемент имеет свойства:
- 🔹
ЛевоеЗначение— поле, по которому идёт отбор (например,"ДатаДокумента"). - 🔹
ВидСравнения— тип условия (Равно,Больше,ВСпискеи т.д.). - 🔹
ПравоеЗначение— значение для сравнения (может быть простым типом, массивом или объектом). - 🔹
Использование— флаг, включающий/отключающий отбор (Истина/Ложь).
⚠️ Внимание: Если вы работаете с управляемыми формами, изменения отборов черезНастройкиКомпоновкиДанныхне всегда сразу отображаются в интерфейсе. Для принудительного обновления используйте методОбновить()у элемента формы.
2. Способ 1: Простое задание значения через свойство Значение
Самый очевидный способ — напрямую присвоить значение отбору по его имени. Этот метод подходит, когда имя отбора заранее известно и не меняется.
Пример кода для установки отбора по дате:
Процедура УстановитьОтборПоДате(НастройкиКомпоновки, ДатаНачала, ДатаОкончания)
НастройкиКомпоновки.Отбор.ДатаДокумента.ВидСравнения = ВидСравненияКомпоновкиДанных.Между;
НастройкиКомпоновки.Отбор.ДатаДокумента.Значение = Новый Массив(ДатаНачала, ДатаОкончания);
КонецПроцедуры
Здесь:
- 📅
ДатаДокумента— имя поля отбора (должно совпадать с именем в схеме СКД). - 🔄
ВидСравненияКомпоновкиДанных.Между— тип условия (альтернативы:Равно,Больше,ВСпискеи др.). - 📊
Новый Массив()— используется для условий типаМеждуилиВСписке.
Этот метод удобен своей простотой, но имеет ограничения:
- ❌ Не работает, если имя отбора содержит специальные символы или пробелы (в таком случае используйте
ЭлементыОтбора). - ❌ Не позволяет динамически добавлять новые отборы — только модифицировать существующие.
3. Способ 2: Работа с коллекцией ЭлементыОтбора
Более гибкий подход — использование коллекции ЭлементыОтбора, которая доступна через свойство Отбор настроек компоновки. Этот метод позволяет:
- 🔍 Добавлять новые отборы динамически.
- 🔄 Менять условия для отборов с нестандартными именами.
- 🗑️ Удалять ненужные отборы.
Пример добавления отбора по контрагенту:
Процедура ДобавитьОтборПоКонтрагенту(НастройкиКомпоновки, СписокКонтрагентов)
НовыйОтбор = НастройкиКомпоновки.Отбор.ЭлементыОтбора.Добавить();
НовыйОтбор.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Контрагент");
НовыйОтбор.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
НовыйОтбор.ПравоеЗначение = СписокКонтрагентов;
НовыйОтбор.Использование = Истина;
КонецПроцедуры
Ключевые моменты:
- 🆔
Новый ПолеКомпоновкиДанных()— создаёт объект поля для отбора. Имя поля ("Контрагент") должно совпадать с именем в схеме СКД. - 📋
ВидСравненияКомпоновкиДанных.ВСписке— используется для проверки вхождения в массив значений. - 🔘
Использование = Истина— активирует отбор (по умолчанию может бытьЛожь).
⚠️ Внимание: При работе с перечислениями или ссылками (например, справочники) правое значение должно быть корректного типа. Если передать строку вместо ссылки, отбор не сработает!
Имя поля отбора существует в схеме СКД|Тип правого значения соответствует типу поля (дата, ссылка, число)|Вид сравнения поддерживается для данного типа поля|Отбор включён (свойство Использование = Истина)-->
4. Способ 3: Динамическое изменение схемы компоновки
Если нужно не только изменить значение отбора, но и добавить новое поле для отбора (которое изначально не было в схеме), потребуется модифицировать саму схему компоновки. Это актуально для динамических отчётов, где поля отборов определяются на лету.
Пример добавления нового поля отбора по сумме документа:
Процедура ДобавитьПолеОтбораПоСумме(СхемаКомпоновки)
// Добавляем поле в набор данных
ПолеСумма = СхемаКомпоновки.НаборыДанных.Элементы[0].Поля.Добавить();
ПолеСумма.Имя = "СуммаДокумента";
ПолеСумма.ПутьКДанным = "СуммаДокумента";
// Добавляем отбор по этому полю
НовыйОтбор = СхемаКомпоновки.Отбор.ЭлементыОтбора.Добавить();
НовыйОтбор.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("СуммаДокумента");
НовыйОтбор.ВидСравнения = ВидСравненияКомпоновкиДанных.Больше;
НовыйОтбор.ПравоеЗначение = 10000;
КонецПроцедуры
Особенности метода:
- 🛠️ Требует прав на изменение схемы компоновки (может быть ограничено в типовой конфигурации).
- 🔄 Изменения схемы применяются ко всем пользователям отчёта, если не использовать персональные настройки.
- ⚡ После изменения схемы нужно обновить настройки компоновки (
НастройкиКомпоновки.Загрузить(СхемаКомпоновки)).
| Способ | Когда использовать | Ограничения |
|---|---|---|
| Прямое присваивание | Простые отборы с известными именами | Не работает с нестандартными именами полей |
Коллекция ЭлементыОтбора |
Динамические отборы, сложные условия | Требует знания структуры СКД |
| Изменение схемы | Добавление новых полей отбора | Может затрагивать всех пользователей |
5. Работа с датами и перечислениями: типичные ошибки
Отборы по датам и перечислениям часто становятся источником ошибок из-за неверного формата данных или неправильного вида сравнения. Рассмотрим ключевые моменты.
Отбор по датам
При установке отбора по дате убедитесь, что:
- 📅 Правое значение — это объект типа
Дата, а не строка. - 🕒 Для условий
Междумассив дат должен содержать ровно два элемента. - 🌍 Учитывается временная зона (если даты приходят из внешних систем).
Пример корректного отбора по текущему месяцу:
НастройкиКомпоновки.Отбор.Дата.ВидСравнения = ВидСравненияКомпоновкиДанных.Между;
НастройкиКомпоновки.Отбор.Дата.Значение = Новый Массив(
НачалоМесяца(ТекущаяДата()),
КонецМесяца(ТекущаяДата())
);
Отбор по перечислениям
Для полей типа Перечисление правое значение должно быть:
- 🔢 Объектом
ЗначениеПеречисления(не строкой!). - 📋 Для условия
ВСписке— массивом таких объектов.
Ошибка, которая приводит к пустому результату:
// НЕПРАВИЛЬНО: передаём строку вместо значения перечисления
НастройкиКомпоновки.Отбор.Статус.Значение = "Завершён";
Правильный вариант:
// ПРАВИЛЬНО: используем значение перечисления
НастройкиКомпоновки.Отбор.Статус.Значение = Перечисления.СтатусыДокументов.Завершён;
Чтобы избежать ошибок с типами данных, используйте функцию ТипЗнч() для проверки правого значения перед установкой отбора. Например: Если ТипЗнч(Значение) <> Тип("Дата") Тогда ...
6. Отборы в управляемых и обычных формах: ключевые различия
Логика работы с отборами в управляемых и обычных формах имеет нюансы, которые важно учитывать.
Управляемые формы
В управляемых формах отчёты СКД обычно размещаются в элементе ПолеHTMLДокумента или ПолеТабличногоДокумента. После изменения отборов необходимо:
- 🔄 Обновить настройки компоновки:
Отчёт.Настройки = НастройкиКомпоновки; - 🖥️ Вызвать метод
Обновить()у элемента формы:ЭлементыФормы.Отчёт.Обновить();
Пример для управляемой формы:
Процедура ПриИзмененииПараметров(Элемент)
НастройкиКомпоновки = Отчёт.Настройки;
НастройкиКомпоновки.Отбор.Дата.Значение = ТекущаяДата();
Отчёт.Настройки = НастройкиКомпоновки;
ЭлементыФормы.Отчёт.Обновить();
КонецПроцедуры
Обычные формы
В обычных формах отчёт СКД часто представлен элементом ПолеТабличногоДокумента. Здесь достаточно обновить настройки:
Процедура УстановитьОтбор()
НастройкиКомпоновки = Отчёт.Настройки;
НастройкиКомпоновки.Отбор.Контрагент.Значение = Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка");
Отчёт.Настройки = НастройкиКомпоновки;
Отчёт.СкомпоноватьРезультат();
КонецПроцедуры
⚠️ Внимание: В тонком клиенте или веб-клиенте некоторые методы (например, СкомпоноватьРезультат()) могут работать иначе, чем в толстом клиенте. Всегда тестируйте отчёты в целевой среде!
Что делать, если отбор не применяется?
Если после программной установки отбора данные в отчёте не фильтруются, проверьте:
1. Тип правого значения — например, для поля типа "СправочникСсылка.Контрагенты" правое значение должно быть ссылкой, а не строкой.
2. Вид сравнения — условие "Равно" не сработает, если поле содержит NULL.
3. Флаг "Использование" — отбор может быть отключён (свойство = Ложь).
4. Обновление отчёта — в управляемых формах требуется явный вызов Обновить().
5. Права доступа — пользователь может не иметь прав на чтение данных, попадающих под отбор.
7. Продвинутые техники: динамические отборы и работа с виртуальными таблицами
Для сложных сценариев (например, когда отборы зависят от действий пользователя или внешних данных) используют динамическое формирование условий.
Динамические отборы на основе пользовательского ввода
Пример: фильтрация документов по произвольному набору реквизитов, выбранных пользователем в таблице значений.
Процедура ПрименитьДинамическиеОтборы(НастройкиКомпоновки, ТаблицаОтборов)
Для Каждого СтрокаОтбора Из ТаблицаОтборов Цикл
НовыйОтбор = НастройкиКомпоновки.Отбор.ЭлементыОтбора.Добавить();
НовыйОтбор.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(СтрокаОтбора.Поле);
НовыйОтбор.ВидСравнения = СтрокаОтбора.ВидСравнения;
НовыйОтбор.ПравоеЗначение = СтрокаОтбора.Значение;
КонецЦикла;
КонецПроцедуры
Отборы по виртуальным таблицам
Если отчёт использует виртуальные таблицы (например, Документ.РеализацияТоваровУслуг.Обороты), имена полей для отбора должны соответствовать структуре виртуальной таблицы. Пример:
НастройкиКомпоновки.Отбор.Период.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Период");
НастройкиКомпоновки.Отбор.Период.ВидСравнения = ВидСравненияКомпоновкиДанных.ВИерархии;
НастройкиКомпоновки.Отбор.Период.ПравоеЗначение = ТекущийДокумент.Дата;
Для виртуальных таблиц с иерархией (например, по периодам) используйте ВидСравненияКомпоновкиДанных.ВИерархии.
При работе с виртуальными таблицами всегда проверяйте доступные поля отбора через конструктор СКД — их имена могут отличаться от имен реквизитов в метаданных.
8. Типичные ошибки и как их избежать
Даже опытные разработчики сталкиваются с проблемами при программной установке отборов. Вот наиболее распространённые ошибки и способы их решения:
| Ошибка | Причина | Решение |
|---|---|---|
| Отбор не применяется | Не вызван метод Обновить() для управляемой формы |
Добавьте ЭлементыФормы.Отчёт.Обновить() |
| Ошибка при сравнении типов | Правое значение не соответствует типу поля (например, строка вместо даты) | Проверяйте типы с помощью ТипЗнч() |
| Пустой результат отчёта | Отбор слишком строгий (например, Равно NULL) |
Используйте ВидСравненияКомпоновкиДанных.Заполнено для проверки на NULL |
| Ошибка "Поле не найдено" | Опечатка в имени поля или оно не добавлено в схему СКД | Проверьте имя поля через конструктор отчёта |
Ещё одна частая проблема — отборы не сохраняются между сеансами. Это происходит, если настройки компоновки не сохранены в пользовательские настройки. Решение:
ПользовательскиеНастройки = НастройкиКомпоновки.ПолучитьНастройки();
ПользовательскиеНастройки.Отбор = НастройкиКомпоновки.Отбор;
НастройкиКомпоновки.Записать(ПользовательскиеНастройки);
Для отладки отборов используйте Сообщить() или ЗаписатьВФайл(), чтобы вывести текущие настройки:
ЗаписатьВФайл(НастройкиКомпоновки.Отбор, "C:\temp\отборы.txt", "UTF-8");
FAQ: Ответы на частые вопросы
Как программно удалить все отборы из СКД?
Чтобы очистить все отборы, пройдите по коллекции ЭлементыОтбора и удалите элементы:
Пока НастройкиКомпоновки.Отбор.ЭлементыОтбора.Количество() > 0 Цикл
НастройкиКомпоновки.Отбор.ЭлементыОтбора.Удалить(0);
КонецЦикла;
Или создайте новый пустой отбор:
НастройкиКомпоновки.Отбор = Новый ОтборКомпоновкиДанных();
Можно ли установить отбор по полю, которого нет в схеме СКД?
Нет, поле должно быть заранее добавлено в схему компоновки (либо в набор данных, либо в ресурсы). Если поля нет, его нужно добавить программно через модификацию схемы (см. Способ 3).
Исключение — виртуальные таблицы с динамическими полями (например, обороты по регистрам), где поля определяются системой.
Как сделать отбор по нескольким значениям (аналог SQL IN)?
Используйте ВидСравненияКомпоновкиДанных.ВСписке и передавайте массив значений:
НастройкиКомпоновки.Отбор.Контрагент.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
НастройкиКомпоновки.Отбор.Контрагент.Значение = Новый Массив(
Справочники.Контрагенты.НайтиПоНаименованию("ООО Альфа"),
Справочники.Контрагенты.НайтиПоНаименованию("ООО Бета")
);
Почему отбор по дате не работает с временной частью?
В 1С:Предприятие даты без времени сравниваются как ДатаНачалаДня. Чтобы учесть время, используйте:
НастройкиКомпоновки.Отбор.Дата.ВидСравнения = ВидСравненияКомпоновкиДанных.БольшеИлиРавно;
НастройкиКомпоновки.Отбор.Дата.Значение = НачалоДня(ТекущаяДата());
Для точного сравнения с временем используйте тип ДатаВремя.
Как передать отборы из формы в отчёт СКД?
Создайте на форме реквизиты для хранения параметров отбора, а затем переносите их в настройки компоновки:
Процедура СформироватьОтчёт(Команда)
НастройкиКомпоновки = Отчёт.Настройки;
Если ЗначениеЗаполнено(ПараметрыОтчёта.ДатаНачала) Тогда
НастройкиКомпоновки.Отбор.Дата.Значение = ПараметрыОтчёта.ДатаНачала;
КонецЕсли;
Отчёт.Настройки = НастройкиКомпоновки;
Отчёт.СкомпоноватьРезультат();
КонецПроцедуры