Почему возникает ошибка «Операция не разрешена в предложении "ГДЕ"» при проведении документа в 1С?

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

При разработке и доработке алгоритмов проведения документов в платформе 1С:Предприятие разработчики нередко сталкиваются с ошибкой выполнения запроса вида {(14, 8)}: Операция не разрешена в предложении "ГДЕ" <<?>>ОстаткиМатериаловОстатки.КоличествоОстаток. Давайте подробно проанализируем причину возникновения этой ошибки, разберем синтаксические требования языка запросов 1С и рассмотрим правильную реализацию контроля остатков.

Причина возникновения ошибки

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

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


ВЫБРАТЬ
    ОстаткиМатериаловОстатки.Материал,
    ОстаткиМатериаловОстатки.НаборСвойств,
    ОстаткиМатериаловОстатки.КоличествоОстаток
ИЗ
    РегистрНакопления.ОстаткиМатериалов.Остатки( , (Материал, НаборСвойств) В
            (ВЫБРАТЬ
                НоменклатураДокумента.Номенклатура,
                НоменклатураДокумента.НаборСвойств
            ИЗ
                НоменклатураДокумента) И Склад = &Склад) КАК ОстаткиМатериаловОстатки
ГДЕ
    ОстаткиМатериаловОстатки.КоличествоОстаток

В приведенном фрагменте в секции ГДЕ указано числовое поле ОстаткиМатериаловОстатки.КоличествоОстаток без какого-либо оператора сравнения. Из-за отсутствия логического выражения парсер запросов 1С выдает синтаксическую ошибку на этапе компиляции и вызова метода Выполнить().

Исправление синтаксической ошибки

Для устранения ошибки достаточно явно указать условие отбора. При использовании новой методики контроля остатков (когда движения уже записаны в базу данных, и мы ищем образовавшиеся отрицательные остатки) необходимо отобрать строки, где количество меньше нуля:


ГДЕ
    ОстаткиМатериаловОстатки.КоличествоОстаток < 0

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

Разберем дополнительные важные нюансы кода проведения документа, которые помогут избежать ошибок блокировок, искажения себестоимости и проблем с производительностью.

  1. Объединение запросов в пакет: Использование нескольких отдельных объектов Запрос с единым МенеджерВременныхТаблиц порождает лишние сетевые вызовы между сервером приложений и СУБД. Рекомендуется объединять запросы в единый текст через точку с запятой (;) и выполнять их методом ВыполнитьПакет().
  2. Передача момента времени в виртуальные таблицы остатков: Вызов РегистрНакопления.ОстаткиМатериалов.Остатки( , ...) без указания первого параметра (Период) приводит к расчету остатков на самую последнюю дату временной шкалы. При перепроведении документа задним числом или восстановлении последовательности будут получены неверные данные. В виртуальные таблицы необходимо передавать &МоментВремени или объект Граница.
  3. Контроль деления на ноль при расчете себестоимости: Если на остатках числится нулевое или отрицательное количество, формула Стоимость / Количество приведет к ошибкам или искажению учетных цен. При полном списании остатка себестоимость должна списываться полностью без деления, чтобы исключить погрешности копеечных округлений.
  4. Управление блокировками: При работе в режиме управляемых блокировок свойство БлокироватьДляИзменения = Истина не заменяет явную установку управляемой блокировки через объект БлокировкаДанных по ключевым аналитическим разрезам (номенклатура, склад) перед чтением остатков.

Исправленный вариант блока контроля остатков

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


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

    Запрос3.УстановитьПараметр("Склад", Склад);
    Запрос3.УстановитьПараметр("МоментВремени", МоментВремени());

    РезультатЗапроса = Запрос3.Выполнить();
    ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();

    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        Сообщение = Новый СообщениеПользователю();
        Сообщение.Текст = "Не хватает " + Строка(-ВыборкаДетальныеЗаписи.КоличествоОстаток) 
            + " ед. материала """ + ВыборкаДетальныеЗаписи.Материал + """" 
            + " из набора свойств """ + ВыборкаДетальныеЗаписи.НаборСвойств + """";
        Сообщение.Сообщить();
        Отказ = Истина;
    КонецЦикла;
КонецЕсли;

Таким образом, для устранения ошибки в предложении ГДЕ обязательно указываем явный логический предикат (в данном случае < 0), а для надежной работы механизма проведения передаем в параметры виртуальной таблицы корректный момент времени документа.

← На главную