Как правильно использовать условие КОГДА в функциях запроса в 1С 7.7?

Программист 1С v7.7 Управленческий учет IT и автоматизация бизнеса
← На главную

При разработке отчетов в платформе 1С:Предприятие 7.7 нередко возникает задача получить в рамках одного запроса несколько разных числовых показателей с индивидуальными условиями. Например, требуется вывести в одной строке по каждой номенклатурной позиции остаток по основному складу и остаток по складу брака либо разделить суммы оборотов на прямые продажи и возвраты.

Для решения подобных задач в языке запросов 1С 7.7 предусмотрена специальная конструкция КОГДА (в англоязычном варианте WHEN), которая накладывает локальный фильтр исключительно на рассчитываемую агрегатную функцию.

Синтаксис и назначение конструкции КОГДА

Разберем базовый синтаксис объявления функции в тексте запроса платформы 1С 7.7:

Синтаксис:

Функция <ИмяФункции> = <ТипФункции>(<Параметр>) [Когда(<Условие>)];

Параметры конструкции:

  1. ИмяФункции — уникальное имя переменной запроса, через которую результат функции будет доступен в результатах обхода.
  2. ТипФункции — имя встроенной агрегатной функции: КонОст, НачОст, Приход, Расход, Сумма, Счёт и др.
  3. Параметр — внутренняя переменная запроса (ресурс регистра или реквизит документа/справочника).
  4. Условие — логическое выражение, при истинности которого значение параметра включается в расчет агрегата.

Главное отличие конструкции КОГДА от секции Условие(...) заключается в области действия: секция Условие(...) фильтрует строки для всего запроса целиком, а условие в КОГДА применяется только к конкретной функции, не затрагивая остальные рассчитываемые показатели.

Примеры практического применения

Рассмотрим типовые сценарии использования локальных условий в запросах.

1. Разделение остатков по группам складов:

Посмотрим на пример запроса, в котором по каждой позиции номенклатуры одновременно рассчитываются конечные остатки по двум разным спискам складов:


// Списки складов должны быть предварительно сформированы в модуле
ВыбСклад1 = СоздатьОбъект("СписокЗначений");
ВыбСклад2 = СоздатьОбъект("СписокЗначений");
// Заполнение списков элементами справочника Склады...

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|Склад = Регистр.ОстаткиТоваров.Склад;
|Товар = Регистр.ОстаткиТоваров.Товар;
|Количество = Регистр.ОстаткиТоваров.Количество;
|Функция КоличествоКонОст1 = КонОст(Количество) КОГДА (Склад В ВыбСклад1);
|Функция КоличествоКонОст2 = КонОст(Количество) КОГДА (Склад В ВыбСклад2);
|Группировка Товар без групп;
|Условие (Товар В ВыбТовар);
|";

Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Пока Запрос.Группировка(1) = 1 Цикл
        Сообщить(Строка(Запрос.Товар) + " | Склад 1: " + Запрос.КоличествоКонОст1 + " | Склад 2: " + Запрос.КоличествоКонОст2);
    КонецЦикла;
КонецЕсли;

2. Разделение оборотов на продажи и возвраты:

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


ТекстЗапроса = "
|Товар = Регистр.Продажи.Товар;
|РасходКво = Регистр.Продажи.Количество;
|Функция РасходСумма = Сумма(РасходКво) КОГДА (РасходКво > 0);
|Функция РасходВозврат = Сумма(РасходКво) КОГДА (РасходКво < 0);
|Группировка Товар;
|";

3. Фильтрация по свойствам документов:

Посмотрим на пример отбора движений только по определенному виду документа:


ТекстЗапроса = "
|ТекДок = Регистр.Заказы.ТекущийДокумент;
|КолЗаказа = Регистр.Заказы.Количество;
|Функция ПолученоПок = Расход(КолЗаказа) КОГДА (ТекДок.Вид() <> ""ЗаказПоставщику"");
|Группировка ТекДок;
|";

Причины ошибок и правила работы с условиями в функциях

Выясним причину, почему запрос с конструкцией КОГДА может выдавать одинаковые или неверные цифры во всех колонках.

  1. Недопустимость динамических вызовов функций в тексте запроса:

    Попытка вызвать пользовательскую функцию прямо внутри секции КОГДА, например: КОГДА (Склад В ВернутьСписокСкладов(...)), приводит к непредсказуемой работе парсера запросов 1С 7.7. Движок платформы вычисляет условие построчно для каждого движения, и повторный динамический возврат объектов может сбоить, вызывая утечки дескрипторов и искажение результата. Все списки значений и фильтры необходимо создавать до сборки текста запроса и обращаться к ним по имени переменной.

  2. Сравнение элементов справочника со строками:

    Если измерение регистра (например, Склад) имеет тип ссылки на справочник, то и список значений (СписокЗначений), передаваемый в оператор В, обязан содержать именно ссылки на элементы справочника, а не их строковые наименования или коды. При несовпадении типов условие всегда будет вычисляться как ложное либо игнорироваться.

  3. Область видимости переменных:

    Переменные списков значений (например, ВыбСклад1), передаваемые в условия запроса, должны быть инициализированы в той же области видимости (локальные переменные процедуры или переменные модуля формы/отчета) и существовать в памяти на момент вызова Запрос.Выполнить(...).

  4. Производительность:

    Следует учитывать, что при расчете КонОст без условий платформа 1С 7.7 берет готовые данные из таблицы итогов регистров. Добавление сложного условия в КОГДА заставляет движок перебирать записи таблицы движений, что на больших базах может заметно замедлить выполнение отчета. В таких случаях альтернативным решением является получение остатков в группировке по измерению с последующей обработкой в ТаблицеЗначений средствами встроенного языка.

← На главную