Как реализовать необязательные условия с логикой ВЫБОР КОГДА в СКД и избежать ошибок

Программист 1С v8.3 (Управляемые формы) Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При работе с Системой компоновки данных (СКД) разработчики часто сталкиваются с необходимостью реализовать гибкую фильтрацию. Типичная задача: если параметр заполнен — фильтруем по нему, если нет — применяем особую логику (например, исключаем определенные записи). Однако попытка написать сложную конструкцию ВЫБОР КОГДА внутри расширения языка запросов (фигурных скобок {}) часто приводит к ошибке "Параметр не указан". Разберем, почему это происходит и как правильно решить эту задачу несколькими способами.

Почему стандартный подход с ВЫБОР КОГДА не работает в ГДЕ

Проанализируем ситуацию. Когда мы помещаем условие в фигурные скобки {ГДЕ...}, мы даем команду препроцессору СКД: "Если параметры внутри этого блока не заполнены, удали весь этот блок из итогового запроса". Однако препроцессор СКД эффективно работает только с простыми сравнениями. Если внутри скобок оказывается сложная логика ВЫБОР КОГДА, препроцессор не всегда может корректно определить, "пустое" ли это условие. В результате часть выражения с параметром остается в запросе, и если пользователь не заполнил значение, СУБД выдает ошибку.

Кроме того, использование ВЫБОР в секции ГДЕ крайне негативно сказывается на производительности. СУБД не может использовать индексы для таких условий (проблема SARGability), что приводит к полному сканированию таблиц (Full Table Scan) и замедлению отчета в десятки раз.

Решение 1: Разделение на простые необязательные условия

Вместо того чтобы пытаться уместить всю логику в одну конструкцию ВЫБОР, разберем, как сделать условия независимыми. Рассмотрим пример, где нам нужно фильтровать по организации и подразделению. Мы можем прописать каждое условие отдельно в фигурных скобках:


{ГДЕ
    ХозрасчетныйОстатки.Организация = &Организация,
    ХозрасчетныйОстатки.Подразделение = &Подразделение}

В этом случае, если &Подразделение не заполнено, СКД просто выкинет вторую строку, оставив только фильтр по организации. Если же нам нужна специфическая логика (например, "если подразделение не указано, исключить обособленные"), лучше вынести это в программную обработку или в параметры самой виртуальной таблицы.

Решение 2: Использование выражений параметров СКД

Посмотрим на более изящный способ настройки через вкладку "Параметры" в схеме компоновки данных. Мы можем создать скрытый параметр, значение которого будет вычисляться автоматически. Это позволяет оставить текст запроса чистым и производительным.

Шаги реализации:

  1. Создадим параметр &СписокПодразделений.
  2. В поле "Выражение" для этого параметра напишем логику на языке выражений СКД:

ВЫБОР 
    КОГДА ЗначениеЗаполнено(&Подразделение) 
    ТОГДА &Подразделение 
    ИНАЧЕ ПолучитьСписокПодразделенийБезОбособленных(&Организация) 
КОНЕЦ

В самом запросе теперь достаточно написать простое и эффективное условие:


{ГДЕ
    ХозрасчетныйОстатки.Подразделение В (&СписокПодразделений)}

Таким образом, СУБД получит готовый список значений или конкретную ссылку, что позволит ей эффективно использовать индексы.

Решение 3: Параметры виртуальных таблиц (Лучшая практика)

Проанализируем работу с виртуальными таблицами, такими как ХозрасчетныйОстатки. Важнейшее правило оптимизации в 1С: условия должны передаваться в параметры виртуальной таблицы, а не в секцию ГДЕ. Если фильтр стоит в ГДЕ, система сначала выберет ВСЕ остатки в память, а потом отсечет лишнее. Если фильтр в параметрах таблицы — выборка ограничится на уровне базы данных.

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


ХозрасчетныйОстатки.Остатки(&Период, , , {Подразделение.* КАК Подразделение, Организация.* КАК Организация})

Обратите внимание на конструкцию {Подразделение.* КАК Подразделение}. Она позволяет СКД автоматически подставлять выбранные пользователем отборы (включая виды сравнения "В списке", "Равно" и т.д.) непосредственно в параметры получения остатков.

Решение 4: Программная модификация в событии ПриКомпоновкеРезультата

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

Рассмотрим пример кода в модуле объекта отчета:


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

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

Подведем итоги

Для создания качественного и быстрого отчета в СКД при работе с необязательными параметрами следует придерживаться следующих рекомендаций:

  1. Избегайте ВЫБОР КОГДА в секции ГДЕ. Это убивает производительность и запутывает препроцессор СКД.
  2. Используйте расширения параметров виртуальных таблиц. Помещайте условия в фигурные скобки внутри параметров Остатки() или Обороты().
  3. Применяйте "Выражения" для параметров. Если нужна сложная логика "Если А, то Б", реализуйте её на вкладке параметров схемы, а в запросе оставьте простое сравнение.
  4. Программная модификация — это мощный инструмент, но используйте его только тогда, когда возможностей декларативной настройки СКД действительно недостаточно.

Помните, что пустая ссылка и неуказанный параметр — это разные вещи для СКД. Если в параметре передана пустая ссылка, СКД считает его заполненным. Чтобы условие полностью исчезло из SQL-запроса, параметр должен быть либо не установлен в настройках, либо выключен (флажок использования).

← На главную