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

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

При разработке сложных отчетов или обработок программисты часто сталкиваются с необходимостью изменять логику отбора данных в зависимости от выбора пользователя. Распространенная ошибка новичков — попытка передать часть логического выражения (например, И Номенклатура = &Значение) напрямую через параметр запроса. В этой статье мы разберем, почему такой подход не работает, и рассмотрим правильные методы реализации динамических условий.

Почему нельзя передать условие через параметр

Прежде всего, проанализируем ситуацию: платформа 1С воспринимает параметры запроса (конструкции, начинающиеся с &) исключительно как значения определенных типов (число, строка, ссылка, дата). Когда вы пытаетесь написать ГДЕ &Условие, система ожидает, что в &Условие будет передано булево значение (Истина или Ложь), а не фрагмент программного кода на языке запросов.

Если же ваша цель — менять само тело запроса (выбирать разные поля или разные операторы сравнения), то обычные параметры здесь не помогут. Попытка вставить логическую конструкцию в параметр приведет к ошибке: "Операция не разрешена в предложении ГДЕ".

Способ 1: Динамическое формирование текста запроса

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

Разберем по шагам, как модифицировать исходный запрос:


ТекстУсловия = "";
Если ТипФильтра = 1 Тогда
    ТекстУсловия = " И (НЕ ТоварыВРознице.СуммаПродажнаяКонечныйОстаток = Инвентаризация.СуммаРознФакт 
                   | ИЛИ НЕ ТоварыВРознице.СуммаПродажнаяКонечныйОстаток = Инвентаризация.СуммаРознУчет)";
ИначеЕсли ТипФильтра = 2 Тогда
    ТекстУсловия = " И НЕ ТоварыВРознице.СуммаПродажнаяКонечныйОстаток = Инвентаризация.СуммаРознФакт";
ИначеЕсли ТипФильтра = 3 Тогда
    ТекстУсловия = " И НЕ ТоварыВРознице.СуммаПродажнаяКонечныйОстаток = Инвентаризация.СуммаРознУчет";
КонецЕсли;

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

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

Способ 2: Использование конструкции ВЫБОР КОГДА

Если вы не хотите менять текст запроса программно, можно использовать логику внутри самого SQL-запроса с помощью функции ВЫБОР. Мы передаем в параметр идентификатор режима (например, число 1, 2 или 3), а запрос "решает", какое условие применить.

Рассмотрим пример реализации:


ГДЕ 
    ВЫБОР 
        КОГДА &Режим = 1 ТОГДА ТоварыВРознице.Сумма <> Инвентаризация.СуммаФакт
        КОГДА &Режим = 2 ТОГДА ТоварыВРознице.Сумма <> Инвентаризация.СуммаУчет
        ИНАЧЕ ИСТИНА 
    КОНЕЦ

Проанализируем ситуацию с производительностью: данный метод кажется удобным, но он имеет существенный недостаток. СУБД (например, MS SQL Server) сложнее оптимизировать такой запрос. Индексы могут перестать использоваться эффективно, что приведет к замедлению работы на больших объемах данных. Поэтому для высоконагруженных систем рекомендуется использовать динамическую сборку текста (Способ 1).

Способ 3: Механизмы СКД (Система компоновки данных)

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

Выясним, как это работает. В тексте запроса СКД вы можете написать:


ВЫБРАТЬ
    Номенклатура,
    СуммаОстаток
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки
{ГДЕ
    Номенклатура.*,
    Склад.*}

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

Способ 4: Программное использование Схемы запроса

Для продвинутых задач существует объект СхемаЗапроса. Он позволяет работать с запросом как с объектной моделью, а не как со строкой. Мы можем программно добавлять условия в коллекцию отборов, не заботясь о расстановке кавычек и соединительных союзов И / ИЛИ.

Рассмотрим краткий пример:


Схема = Новый СхемаЗапроса;
Схема.УстановитьТекст(ТекстВашегоЗапроса);
ОператорВыбора = Схема.Запросы[0].Операторы[0];
// Добавляем новое условие в секцию ГДЕ
ОператорВыбора.Отбор.Добавить("Номенклатура = &ВыбНоменклатура");

Запрос.Текст = Схема.ПолучитьТекст();

Использование СхемаЗапроса минимизирует риск синтаксических ошибок, которые часто возникают при ручной склейке строк.

Рекомендации по оптимизации и типичные ошибки

  1. Параметры виртуальных таблиц: Всегда старайтесь выносить условия по измерениям (Склад, Номенклатура) в параметры виртуальных таблиц (например, в ОстаткиИОбороты), а не в секцию ГДЕ. Это значительно ускоряет выборку.
  2. Обработка NULL: Помните, что при использовании ЛЕВОЕ СОЕДИНЕНИЕ или ПОЛНОЕ СОЕДИНЕНИЕ отсутствующие данные заменяются значением NULL. Любое сравнение с NULL (например, Сумма <> 100) даст результат "Ложь", даже если сумма фактически не равна 100. Используйте функцию ЕСТЬNULL(Поле, 0).
  3. Сравнение периодов: Вместо сложных конструкций с ДОБАВИТЬКДАТЕ и НАЧАЛОПЕРИОДА внутри запроса, лучше заранее рассчитать начало и конец нужного периода в коде 1С и передать их как готовые параметры даты.
  4. Оператор НЕ: Старайтесь избегать конструкции НЕ Поле = Значение. Используйте стандартный оператор "не равно" — <>. Это делает код более читаемым и привычным для SQL-оптимизаторов.

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

← На главную