Почему в запросе 1С 7.7 не срабатывает условие отбора по перечислению

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

При написании встроенных («чёрных») запросов в платформе 1С:Предприятие 7.7 разработчики нередко сталкиваются с ситуацией, когда условия фильтрации данных в секции Условие(...) отрабатывают некорректно: строки, которые должны быть исключены, всё равно попадают в результат выборки. Рассмотрим типичную ситуацию на примере регистра «Прибыль» и разберем, почему условия сравнения с перечислениями могут игнорироваться, а также как правильно выстраивать логику отбора.

Анализ проблемы и исходного запроса

Проанализируем пример запроса, в котором возникла ошибка:


Период с НачДата по ДатаЗП;
Пол = Регистр.Прибыль.Товар.ПолТовара;
Тов = Регистр.Прибыль.Товар;
Скл = Регистр.Прибыль.Склад;
Гор = Регистр.Прибыль.Склад.Город;
Поставщик = Регистр.Прибыль.Поставщик;    
Фирма = Регистр.Прибыль.Фирма;
Клиент = Регистр.Прибыль.Клиент;
Себест = Регистр.Прибыль.Стоимость;
Выруч = Регистр.Прибыль.Выручка;
КолПрод = Регистр.Прибыль.Количество;
Группировка Пол;
Группировка Тов Без Групп;
Группировка Поставщик Без Групп;
Функция Кол = Сумма(КолПрод);
Функция Себ = Сумма(Себест);
Функция Выр = Сумма(Выруч);
Условие (Тов в СписокТоваров); 
Условие (Пол <> Перечисление.Пол.Мужской); 
Условие (Пол <> Перечисление.Пол.Женский);

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

Причина 1: Несоответствие типов перечислений в конфигурации

Самая распространенная причина ошибки — использование в условии значения из другого перечисления. В конфигурациях 1С 7.7 могут сосуществовать похожие объекты метаданных, например, Перечисление.Пол (применяется для физических лиц или сотрудников) и Перечисление.ПолТовара (реквизит справочника номенклатуры).

Платформа 1С 7.7 строго проверяет типы объектов. Сравнение значения типа Перечисление.ПолТовара.Мужской со значением Перечисление.Пол.Мужской всегда возвращает результат «не равно» (Ложь при сравнении на равенство и Истина при сравнении через <>). Вследствие этого условие Пол <> Перечисление.Пол.Мужской выполняется абсолютно для всех строк регистра, и фильтрация не срабатывает.

Для исправления достаточно указать правильный идентификатор перечисления, соответствующий типу реквизита номенклатуры:


Условие (Пол <> Перечисление.ПолТовара.Мужской);
Условие (Пол <> Перечисление.ПолТовара.Женский);

Причина 2: Исключение набора значений через СписокЗначений

Когда требуется исключить сразу несколько значений, перечисление условий через оператор <> может усложнять чтение кода. В 1С 7.7 несколько строк Условие(...) автоматически связываются логическим оператором И. Если логика усложняется, надежнее использовать передачу списка исключений через объект СписокЗначений с проверкой через отрицание.

Разберем по шагам, как реализовать этот подход:

  1. Перед формированием и выполнением текста запроса создаем и заполняем список исключаемых значений.
  2. В тексте запроса используем оператор НЕ (... В ...).

Посмотрим на пример программного кода:


СписокИсключений = СоздатьОбъект("СписокЗначений");
СписокИсключений.Добавить(Перечисление.ПолТовара.Мужской);
СписокИсключений.Добавить(Перечисление.ПолТовара.Женский);

ТекстЗапроса = "
|Период с НачДата по ДатаЗП;
|Тов = Регистр.Прибыль.Товар;
|Пол = Регистр.Прибыль.Товар.ПолТовара;
|Поставщик = Регистр.Прибыль.Поставщик;
|КолПрод = Регистр.Прибыль.Количество;
|Группировка Пол;
|Группировка Тов Без Групп;
|Функция Кол = Сумма(КолПрод);
|Условие (Тов В СписокТоваров);
|Условие (НЕ (Пол В СписокИсключений));
|";

Причина 3: Проверка пустых и незаполненных значений

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

Для отбора строк с незаполненным или, наоборот, заполненным реквизитом во встроенном языке запросов 1С 7.7 применяется системная функция ПустоеЗначение():


// Отбор только тех товаров, у которых пол не указан:
Условие (ПустоеЗначение(Пол) = 1);

// Отбор только тех товаров, у которых пол заполнен:
Условие (ПустоеЗначение(Пол) = 0);

Оптимизация производительности запроса

Обратим внимание на обращение к реквизитам через точку в строке Пол = Регистр.Прибыль.Товар.ПолТовара;. В платформе 1С 7.7 разыменование через несколько точек не индексируется и приводит к тому, что при обработке каждой строки движений регистра платформа выполняет отдельное обращение к таблице справочника товаров.

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


СписокНужныхТоваров = СоздатьОбъект("СписокЗначений");
СпрТовары = СоздатьОбъект("Справочник.Номенклатура");
СпрТовары.ВыбратьЭлементы();

Пока СпрТовары.ПолучитьЭлемент() = 1 Цикл
    Если СпрТовары.ЭтоГруппа() = 1 Тогда
        Продолжить;
    КонецЕсли;
    
    // Проверяем условия по реквизитам заранее
    Если (СпрТовары.ПолТовара <> Перечисление.ПолТовара.Мужской) 
       И (СпрТовары.ПолТовара <> Перечисление.ПолТовара.Женский) Тогда
        СписокНужныхТоваров.Добавить(СпрТовары.ТекущийЭлемент());
    КонецЕсли;
КонецЦикла;

// В самом запросе фильтруем только по отобранному списку:
// Условие (Тов В СписокНужныхТоваров);

Такой подход исключает множественные обращения к реквизитам справочника в цикле обработки регистра и гарантирует корректную отработку условий без риска несовпадения типов данных.

← На главную