Работа с отчетами на платформе 1С:Предприятие 8.3 часто требует гибкости, которую стандартные настройки пользовательского интерфейса не всегда могут обеспечить. Разработчикам приходится решать задачу динамического формирования структуры отчета в зависимости от сложной бизнес-логики. Одним из самых востребованных сценариев является необходимость программно добавить отбор в схему компоновки данных (СКД) перед выводом результата.
Эта процедура позволяет фильтровать данные на уровне запроса или после выборки, не требуя от пользователя ручного ввода параметров каждый раз. Понимание внутреннего устройства объекта НастройкиКомпоновкиДанных и его коллекции Отборы является ключевым для создания эффективных и быстрых отчетов. В этом материале мы детально разберем алгоритм действий, типичные ошибки и нюансы работы с разными типами полей.
Для начала работы вам потребуется объект настроек, который обычно получается через свойство Макет.ПараметрыКомпоновкиДанных или создается заново. Манипуляции с отборами производятся до момента создания объекта КомпоновщикНастроек или перед выполнением метода СкомпоноватьРезультат.
Структура коллекции отборов и базовый принцип работы
Коллекция отборов в СКД представляет собой список объектов типа ЭлементОтбораКомпоновкиДанных. Каждый такой элемент описывает одно условие фильтрации. Когда вы решаете программно добавить отбор, вы фактически создаете новый экземпляр этого объекта, заполняете его обязательные свойства и добавляете в коллекцию. Система автоматически преобразует эти настройки в конструкцию ГДЕ языка запросов.
Основными свойствами, которые необходимо заполнить, являются Использование, Поле, ВидСравнения и Значение. Свойство Использование определяет, активно ли данное условие в текущий момент. Если оно установлено в Ложь, отбор игнорируется движком компоновки. Это удобно для временного отключения условий без их физического удаления из коллекции.
Поле отбора может ссылаться как на поле набора данных, так и на параметр компоновки. Это различие критично: отбор по параметру влияет на ввод данных пользователем, а отбор по полю набора данных жестко фильтрует результат выборки. Неправильный выбор типа поля может привести к тому, что отчет не покажет нужные данные или выдаст ошибку при выполнении.
При добавлении отбора программно всегда проверяйте свойство "Использование". Если оно не установлено в "Истина", условие не будет применено к запросу, даже если все остальные параметры заполнены верно.
Рассмотрим базовый пример создания отбора. Вам нужно создать новый элемент, указать путь к полю и задать значение. Путь к полю формируется с использованием точек, если речь идет о вложенных структурах, или напрямую, если поле находится в корневом наборе данных. Значение должно строго соответствовать типу данных поля, иначе возникнет ошибка преобразования типов.
Создание простого отбора по конкретному значению
Наиболее частая задача — отфильтровать данные по конкретному идентификатору или строковому значению. Например, нужно показать документы только определенного контрагента или товары из конкретной номенклатурной группы. Для этого используется вид сравнения Равно. В коде это реализуется через создание нового элемента в коллекции Настройки.Отборы.
Важно правильно сформировать объект значения. Если поле является ссылкой на справочник, значение должно быть типа СправочникСсылка. Если это число — тип Число. Платформа 1С строго типизирована, и попытка передать строку туда, где ожидается ссылка, приведет к исключению во время выполнения отчета. Используйте конструкторы объектов или методы получения ссылок для подготовки данных.
Код для добавления такого отбора выглядит лаконично, но требует внимания к деталям. Сначала получаем ссылку на коллекцию отборов, затем создаем новый элемент. После этого заполняем свойства. Особое внимание уделите свойству ВидСравнения, которое перечисляет все доступные операторы: равно, не равно, больше, меньше и другие.
Настройки = Макет.ПараметрыКомпоновкиДанных;
НовыйОтбор = Настройки.Отборы.Добавить();
НовыйОтбор.Использование = Истина;
НовыйОтбор.Поле = Новый ПолеКомпоновкиДанных("Номенклатура");
НовыйОтбор.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
НовыйОтбор.Значение = СсылкаНаНоменклатуру;
Если необходимо отфильтровать данные по нескольким значениям одного поля (например, "Входит в список"), следует использовать вид сравнения ВГруппе. В этом случае свойство Значение должно содержать массив значений или специальный объект списка. Это позволяет избежать создания множества одинаковых отборов с оператором ИЛИ, делая запрос более оптимальным.
☑️ Алгоритм создания отбора
Работа с отборами по периодам и датам
Фильтрация по датам является одной из самых специфических задач в разработке отчетов 1С. Даты могут храниться в разных форматах, а пользователь часто оперирует периодами (месяц, квартал, год). При программном добавлении отбора по дате необходимо учитывать тип поля: это может быть конкретная дата, начало периода или конец периода.
Частая ошибка разработчиков заключается в попытке сравнить дату с датой временем без учета временной составляющей. Если в базе данных время хранения установлено в секунды или миллисекунды, простое сравнение Равно может не сработать для даты "01.01.2026", так как в базе она сохранена как "01.01.2026 00:00:00". В таких случаях рекомендуется использовать диапазоны.
Для реализации отбора по периоду "с.. по.." обычно создают два отдельных элемента отбора: один с видом сравнения БольшеИлиРавно для начальной даты, другой с МеньшеИлиРавно для конечной. Логическое соединение между ними по умолчанию является И, что обеспечивает выборку данных строго внутри заданного интервала.
| Вид сравнения | Описание оператора | Пример использования |
|---|---|---|
| Равно | Точное совпадение значения | Дата = 01.01.2026 |
| БольшеИлиРавно | Значение больше или равно указанному | Дата >= 01.01.2026 |
| МеньшеИлиРавно | Значение меньше или равно указанному | Дата <= 31.01.2026 |
| ВИнтервале | Значение находится внутри интервала | Дата BETWEEN.. AND.. |
При работе с полями типа Период (например, Регистры Бухгалтерии), система компоновки данных автоматически подставляет нужные поля виртуальной таблицы (Период, ПериодКонец). Однако при программном добавлении отбора вы должны явно указывать, к какой части периода относится условие, если это не делается автоматически через параметры периода.
Использование сложных условий и логических операторов
Стандартная коллекция отборов поддерживает только логическое соединение И между всеми элементами. Это означает, что строка данных должна удовлетворять всем добавленным условиям одновременно. Но что делать, если требуется логика ИЛИ? Например, выбрать документы со статусом "Проведен" ИЛИ "Помечен на удаление".
Для реализации сложной логики в СКД существует свойство Группировка у элемента отбора. Однако, прямое создание групп ИЛИ через программный интерфейс коллекции Отборы имеет свои ограничения в разных версиях платформы. Часто разработчики прибегают к хитрости: они добавляют несколько отборов на одно и то же поле с разными значениями, но это все равно даст результат И.
Настоящее решение для сложных условий лежит в плоскости использования Пользовательских полей или модификации самого Запроса в наборе данных перед компоновкой. Если же необходимо остаться в рамках настроек СКД, можно использовать свойство ВидСравнения равное ВГруппе для одного поля, что эквивалентно ИЛИ для значений этого поля.
⚠️ Внимание: Попытка реализовать сложную логику (ИЛИ между разными полями) исключительно через коллекцию
Отборыбез группировок может привести к неверным результатам. В таких случаях надежнее создать вычисляемое поле в запросе, которое вернет 1 или 0 в зависимости от условия, и делать отбор уже по этому полю.
Также стоит упомянуть о вложенных отборах. В некоторых конфигурациях и версиях платформы доступна возможность создания групп отборов. Элемент отбора может содержать собственную коллекцию вложенных отборов. Это позволяет строить деревья условий, где внутри одной ветви действует одно логическое правило, а внутри другой — иное.
Особенности отборов для полей с типом "Список значений"
Когда пользователю требуется выбрать несколько элементов из справочника (например, несколько складов или организаций), в настройках отчета используется поле с типом СписокЗначений. Программная установка такого отбора требует особого подхода к формированию значения. Вы не можете просто передать массив ссылок в свойство Значение обычного отбора.
Необходимо создать объект типа СписокЗначений, заполнить его нужными элементами и уже этот объект присвоить свойству Значение элемента отбора. При этом вид сравнения должен быть установлен в ВГруппе. Это сигнализирует движку СКД, что нужно проверить вхождение значения поля в переданный список.
СписокСкладов = Новый СписокЗначений;
СписокСкладов.Добавить(Склад1);
СписокСкладов.Добавить(Склад2);
Отбор = Настройки.Отборы.Добавить();
Отбор.Поле = Новый ПолеКомпоновкиДанных("Склад");
Отбор.ВидСравнения = ВидСравненияКомпоновкиДанных.ВГруппе;
Отбор.Значение = СписокСкладов;
Важно контролировать пустые списки. Если список значений пуст, отбор может либо выбрать все данные (если логика интерпретирует пустой список как отсутствие ограничений), либо ничего не выбрать. Поведение зависит от конкретной реализации обработчика СКД. Рекомендуется явно проверять количество элементов в списке перед добавлением отбора.
Еще один нюанс — типизация элементов списка. Все элементы в СписокЗначений должны быть совместимы с типом поля отбора. Если поле принимает только ссылки на справочники, попытка добавить туда строку или число вызовет ошибку валидации настроек перед запуском отчета.
Что делать, если список значений слишком большой?
Если список содержит сотни элементов, передача его через отбор СКД может замедлить формирование запроса. В таких случаях эффективнее передать список во временную таблицу и сделать соединение в тексте запроса набора данных.
Очистка и управление существующими отборами
При динамическом формировании отчета часто возникает ситуация, когда нужно сначала очистить все ранее установленные отборы, а затем добавить новые. Это актуально для отчетов, которые работают в разных режимах (например, "детальный" и "сводный"). Метод Очистить() коллекции Отборы позволяет полностью удалить все условия фильтрации.
Однако, простое удаление может быть недостаточным, если в настройках макета определены отборы по умолчанию. В таком случае после очистки они могут восстановиться при повторной инициализации компоновщика. Правильный подход — работать с копией настроек или явно управлять флагом Использование для каждого элемента, вместо физического удаления.
Удаление конкретных отборов требует итерации по коллекции. Поскольку коллекция является динамической, удаление элемента во время цикла требует осторожности. Лучшей практикой является сбор индексов удаляемых элементов или проход по коллекции в обратном порядке, чтобы не сбить индексы оставшихся элементов.
⚠️ Внимание: Никогда не модифицируйте коллекцию
Отборыв циклеДля Каждогопрямым удалением текущего элемента. Это приведет к ошибке выполнения или пропуску элементов. Используйте циклДляпо индексам в обратном порядке или сформируйте список индексов на удаление заранее.
Также стоит помнить о приоритете отборов. Отборы, добавленные программно, могут перекрываться отборами, заданными в макете компоновки данных, если они настроены на одно и то же поле с разными условиями. В случае конфликта система обычно объединяет условия через логическое И, что может сузить выборку сильнее, чем планировалось.
Диагностика и отладка сформированных отборов
Когда отчет работает не так, как ожидается, первым делом нужно проверить, какие именно отборы были сформированы. В режиме предприятия это можно сделать через кнопку "Показать настройки" в интерфейсе отчета, переключившись на вкладку "Отборы". Но при программном добавлении эти настройки могут быть скрыты от пользователя.
Для отладки полезно выводить содержимое коллекции отборов в журнал регистрации или во временное окно сообщения перед запуском компоновки. Проанализируйте свойства Поле и Значение. Убедитесь, что путь к полю соответствует именам полей в наборах данных макета. Опечатка в имени поля приведет к тому, что отбор просто не применится.
Используйте метод ПолучитьТекстЗапроса у объекта компоновщика (если версия платформы позволяет) или включите логирование SQL-запросов в конфигураторе. Анализ полученного текста запроса покажет, как именно интерпретировались ваши программные отборы в конструкцию WHERE. Это самый надежный способ понять, почему данные не фильтруются.
Текст запроса, сгенерированный компоновщиком, — это истина в последней инстанции. Если вы видите отбор в настройках, но его нет в тексте запроса, значит, свойство "Использование" ложно или тип значения не совместим с полем.
Можно ли добавить отбор после того, как отчет уже сформирован?
Нет, отбор влияет на процесс выборки данных из базы. После того как результат скомпонован и выведен на экран, изменение настроек отбора требует повторного выполнения запроса. Вы должны изменить настройки, вызвать метод СкомпоноватьРезультат заново и вывести новую таблицу.
Как программно скрыть добавленный отбор от пользователя в интерфейсе?
Свойство ПользовательскаяВидимость у элемента отбора позволяет управлять его отображением в диалоге настроек. Установив его в Ложь, вы сделаете отбор невидимым для пользователя, но он продолжит работать при формировании отчета.
В чем разница между отбором в наборе данных и отбором в параметрах?
Отбор в параметрах влияет на экран ввода начальных значений (параметры отчета). Отбор в наборе данных фильтрует уже выбранные записи. Программное добавление чаще делается именно в отборы набора данных для жесткой фильтрации, не зависящей от ввода пользователя.
Почему отбор по строковому полю не работает с частью текста?
По умолчанию вид сравнения Равно требует полного совпадения. Для поиска части текста используйте вид сравнения Подобно (с символами подстановки %) или НачинаетсяС, если такая опция доступна в вашей версии платформы для данного типа поля.
Можно ли использовать переменные запроса в программных отборах СКД?
Прямо в значение отбора СКД переменную запроса подставить нельзя, так как это объект конфигурации. Однако вы можете вычислить значение переменной в коде 1С, получить из нее конкретное значение и уже его присвоить свойству Значение элемента отбора.