Как реализовать необязательные условия и параметры в динамическом списке 1С?

Программист 1С v8.3 (Управляемые формы)
← На главную

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

Анализ проблемы: почему стандартный запрос не всегда работает

Рассмотрим ситуацию, когда в зависимости от режима формы нам нужно фильтровать список либо на конкретную &ДатаСреза, либо за определенный период (&ДатаНачала и &ДатаОкончания). Если мы просто пропишем все эти параметры в секции ГДЕ, платформа 1С потребует их обязательной инициализации. Динамический список базируется на Системе компоновки данных (СКД), которая на лету генерирует SQL-запрос. Если параметр заявлен в тексте запроса, но не передан в коллекцию Параметры, выполнение прерывается с ошибкой.

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

Способ 1: Программная модификация текста запроса

Это самый гибкий метод, который позволяет полностью перестроить логику выборки. Если условия принципиально разные (например, в одном случае мы смотрим срез последних в регистре сведений, а в другом — обороты), проще всего заменить текст запроса целиком. Подобную гибкость в настройке логики при работе с кадровыми сведениями обеспечивает перенос между базами ЗУП 3 с корректировкой кода.

Рассмотрим пример реализации в коде формы:


&НаСервере
Процедура НастроитьДинамическийСписок(РежимПериода)
    
    БазовыйТекст = 
    "ВЫБРАТЬ
    |   СправочникФизлица.Ссылка,
    |   СправочникФизлица.Наименование
    |ИЗ
    |   Справочник.ФизическиеЛица КАК СправочникФизлица
    |ГДЕ
    |   СправочникФизлица.Ссылка В (&Подзапрос)";
    
    Если РежимПериода Тогда
        ТекстПодзапроса = 
        "ВЫБРАТЬ Сотрудник.ФизическоеЛицо 
        |ИЗ РегистрСведений.ИзмененияНачислений.СрезПоследних(&ДатаСреза, )";
        Список.Параметры.УстановитьЗначениеПараметра("ДатаСреза", Объект.ДатаОтбора);
    Иначе
        ТекстПодзапроса = 
        "ВЫБРАТЬ Сотрудник.ФизическоеЛицо 
        |ИЗ РегистрСведений.ИзмененияНачислений 
        |ГДЕ Период МЕЖДУ &ДатаНачала И &ДатаОкончания";
        Список.Параметры.УстановитьЗначениеПараметра("ДатаНачала", Объект.НачалоПериода);
        Список.Параметры.УстановитьЗначениеПараметра("ДатаОкончания", Объект.КонецПериода);
    КонецЕсли;
    
    Список.ТекстЗапроса = СтрЗаменить(БазовыйТекст, "&Подзапрос", ТекстПодзапроса);
    
КонецПроцедуры

Важный момент: при ручной замене текста запроса убедитесь, что в свойствах динамического списка включена галочка «Автозаполнение». Это позволит платформе корректно обновить состав доступных полей и параметров после смены текста.

Способ 2: Использование конструкции «Параметр-флаг»

Если вы не хотите менять текст запроса программно, можно использовать логическое условие в самом запросе. Этот метод заставляет СУБД игнорировать часть фильтра, если передан соответствующий флаг.

Рассмотрим, как это выглядит в тексте запроса:


ГДЕ (&ИспользоватьДатуСреза = ЛОЖЬ ИЛИ Регистр.Период <= &ДатаСреза)
  И (&ИспользоватьПериод = ЛОЖЬ ИЛИ (Регистр.Период >= &ДатаНачала И Регистр.Период <= &ДатаОкончания))

В этом случае нам необходимо инициализировать все параметры при открытии формы, даже если они не используются. Например, передать пустую дату и Ложь в качестве флага. Однако помните: такой подход может усложнить план запроса для SQL-сервера, если условий станет слишком много.

Способ 3: Использование фигурных скобок (Синтаксис СКД)

Поскольку динамический список — это СКД, мы можем использовать возможности «необязательных» элементов запроса через фигурные скобки {}. Это самый «чистый» способ с точки зрения платформы.

Проанализируем пример с параметрами виртуальных таблиц:


ВЫБРАТЬ
    ФизЛица.Ссылка
ИЗ
    Справочник.ФизическиеЛица КАК ФизЛица
ГДЕ
    ФизЛица.Ссылка В (
        ВЫБРАТЬ Сотрудник.ФизическоеЛицо
        ИЗ РегистрСведений.ЕРМ_ИзмененияПлановыхНачислений.СрезПоследних({&ДатаСреза}, )
    )

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

Оптимизация производительности: избегаем вложенных запросов

Выясним одну критическую деталь, на которую часто не обращают внимания. Использование конструкции ГДЕ Ссылка В (ВЫБРАТЬ...) в динамических списках — это плохая практика. Динамический список выполняет запросы порциями при скроллинге. Если внутри есть вложенный запрос, СУБД будет вынуждена выполнять его многократно, что приведет к «тормозам» интерфейса.

Проанализируем, как заменить вложенный запрос на СОЕДИНЕНИЕ. Рассмотрим правильную структуру запроса для динамического списка:


ВЫБРАТЬ
    СправочникФизическиеЛица.Ссылка КАК Ссылка,
    СправочникФизическиеЛица.Наименование КАК Наименование
ИЗ
    Справочник.ФизическиеЛица КАК СправочникФизическиеЛица
    // Используем ВНУТРЕННЕЕ СОЕДИНЕНИЕ вместо оператора "В"
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ (
        ВЫБРАТЬ РАЗЛИЧНЫЕ
            Изменения.Сотрудник.ФизическоеЛицо КАК ФизЛицо
        ИЗ
            РегистрСведений.ЕРМ_ИзмененияПлановыхНачислений.СрезПоследних({&ДатаСреза}, ) КАК Изменения
        {ГДЕ
            Изменения.ДатаНачала >= &ДатаНачала,
            Изменения.ДатаОкончания <= &ДатаОкончания}
    ) КАК ОтработанныеФизЛица
    ПО СправочникФизическиеЛица.Ссылка = ОтработанныеФизЛица.ФизЛицо

Преимущества такого подхода:

  1. Скорость: SQL-сервер гораздо эффективнее обрабатывает JOIN, чем подзапросы в условии WHERE.
  2. Гибкость: Использование фигурных скобок в секции ГДЕ внутри подзапроса позволяет пользователю настраивать дополнительные отборы через стандартное меню «Настроить список».
  3. Стабильность: Вы избегаете проблем с блокировками и избыточным чтением данных.

Рекомендации по реализации

Подведем итог и составим пошаговый план действий для реализации динамических условий:

  1. Определите характер условий: Если фильтры меняются радикально — используйте подмену ТекстЗапроса. Если фильтры дополняют друг друга — используйте расширение запроса через {}.
  2. Используйте параметры СКД: Вместо констант в запросе всегда используйте параметры, помещенные в фигурные скобки. Это избавит вас от необходимости проверять наличие каждого параметра в коде.
  3. Откажитесь от вложенных запросов: Всегда старайтесь связать основные данные с уточняющими регистрами через левое или внутреннее соединение. Проверку корректности движений по регистрам после изменения сложных запросов выполняет автоматическая сверка бухгалтерских и налоговых проводок.
  4. Программный отбор: Помните, что для простых условий (равенство, вхождение в список) лучше использовать Список.Отбор.Элементы.Добавить(). Это наиболее быстрый и безопасный способ фильтрации, не требующий модификации текста запроса.

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

← На главную