Ошибка в запросе "неверные параметры Сумма": почему возникает при переходе с 8.1 на 8.2 и как исправить?

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

При обновлении платформы 1С или переносе конфигураций (например, "Управление торговлей") с версии 8.1 на 8.2 и выше (8.3), разработчики часто сталкиваются с ситуацией, когда ранее работавший код начинает выдавать ошибки. Одна из самых распространенных ошибок звучит так: "Ошибка в запросе: неверные параметры "Сумма"".

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

Суть проблемы: анализ исходного кода

Давайте посмотрим на ситуацию, описанную автором. Имеется сложный запрос, который собирает данные из разных источников (Регистры накопления, Документы) с помощью оператора ОБЪЕДИНИТЬ. После объединения данных происходит группировка и суммирование показателей во внешнем запросе.

Упрощенная структура проблемного запроса выглядит следующим образом:


ВЫБРАТЬ
    ...
    Сумма(НетТТН) как НетТТН
ИЗ
(
    ВЫБРАТЬ
        ...
        NULL КАК НетТТН
    ИЗ РегистрНакопления...
    
    ОБЪЕДИНИТЬ
    
    ВЫБРАТЬ
        ...
        NULL КАК НетТТН
    ИЗ Документ.Реестр...
    
    ОБЪЕДИНИТЬ
    
    ВЫБРАТЬ
        ...
        NULL КАК НетТТН
    ИЗ Документ.СХН...
) КАК Данные
СГРУППИРОВАТЬ ПО ...

Обратите внимание на поле НетТТН. В примере автора оно присутствует во всех частях объединения, и во многих случаях оно задано явно как NULL.

Почему возникает ошибка "Неверные параметры"?

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

Агрегатная функция СУММА предназначена для работы исключительно с числовыми типами данных. Вы не можете сложить строки, даты или ссылки. Также вы не можете сложить "Ничто" (NULL), если система не знает, что это "Ничто" должно быть числом.

В платформе 8.1 механизм типизации был более мягким (или "ленивым"). Если в колонке были только NULL, система могла проигнорировать это на этапе построения плана запроса или неявно привести тип в момент выполнения.

Начиная с версии 8.2, оптимизатор запросов стал строже. Рассмотрим алгоритм его действий:

  1. Система анализирует подзапрос внутри скобок.
  2. Она видит, что поле НетТТН в первой выборке — это NULL.
  3. Она смотрит на вторую выборку — там тоже NULL.
  4. Она смотрит на третью выборку — и там NULL.
  5. Вывод системы: Тип колонки НетТТН — это неопределенный тип (NULL), так как нигде не встретилось явного указания на Число, Строку или Дату.
  6. Далее выполняется внешний запрос: Сумма(НетТТН).
  7. Система видит попытку применить математическую функцию СУММА к полю, которое не является числом.
  8. Результат: Ошибка компиляции запроса "Неверные параметры".

Теперь, когда мы выяснили причину, давайте перейдем к методам решения.

Решение №1: Замена NULL на 0 (Самый быстрый способ)

Самый простой способ подсказать системе, что поле должно быть числовым — это заменить NULL на числовой литерал 0 хотя бы в одном из подзапросов (а лучше во всех для единообразия).

Как только оптимизатор увидит цифру 0, он поймет: "Ага, в этой колонке хранятся числа". Следовательно, тип всей колонки в результате объединения станет Число, и функция СУММА отработает корректно.

Изменим наш код:


ВЫБРАТЬ
    ...
    Сумма(НетТТН) как НетТТН
ИЗ
(
    ВЫБРАТЬ
        ...
        0 КАК НетТТН  // Было NULL
    ИЗ РегистрНакопления...
    
    ОБЪЕДИНИТЬ
    
    ВЫБРАТЬ
        ...
        0 КАК НетТТН // Было NULL
    ИЗ Документ.Реестр...
...

Этот метод помог автору темы и является вполне рабочим решением для простых ситуаций.

Решение №2: Явное типизирование через ВЫРАЗИТЬ (Профессиональный подход)

Хотя замена на ноль работает, в сложной разработке считается хорошим тоном явно указывать типы полей, особенно если запрос может быть использован в Системе Компоновки Данных (СКД) или если важна точность (разрядность) чисел.

Используйте функцию ВЫРАЗИТЬ (CAST). Это дает четкую инструкцию платформе: "Здесь пусто, но считай это полем числового типа определенной длины".

Пример правильного кода:


ВЫБРАТЬ
    ...
    ВЫРАЗИТЬ(NULL КАК ЧИСЛО(15, 2)) КАК НетТТН
ИЗ ...

Преимущества этого метода:

Решение №3: Обработка во внешнем запросе

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

Используйте конструкцию ЕСТЬNULL внутри суммы:

Сумма(ЕСТЬNULL(НетТТН, 0)) как НетТТН

Однако, этот метод может не сработать, если ошибка возникает на этапе предварительной проверки типов (компиляции запроса), а не выполнения. В случае с платформой 8.2+ ошибка "Неверные параметры" часто вылетает именно до выполнения, поэтому система даже не дойдет до вычисления ЕСТЬNULL. Поэтому Решение №1 и №2 являются предпочтительными.

Ошибочные подходы: чего делать не стоит

В обсуждении прозвучало предложение заменить функцию СУММА на МАКСИМУМ. Давайте разберем, почему это опасно.

Предложение:

МАКСИМУМ(НетТТН) как НетТТН

Почему это "сработает": Функция МАКСИМУМ (MAX) универсальна. Она умеет сравнивать числа, строки, даты и даже булево. Поэтому ошибка типизации исчезнет.

Почему это неправильно: Вы меняете логику отчета. Функция СУММА складывает все значения в группе. Функция МАКСИМУМ выбирает одно наибольшее.

Пример: У контрагента есть две накладные с долгом 100 рублей и 200 рублей.
СУММА вернет 300 (общий долг).
МАКСИМУМ вернет 200.
Отчет покажет неверные цифры, и бухгалтер будет дезинформирован. Используйте этот метод только если вы абсолютно уверены, что вам не нужно суммирование.

Важное замечание: ОБЪЕДИНИТЬ vs ОБЪЕДИНИТЬ ВСЕ

Анализируя код автора, мы видим использование оператора ОБЪЕДИНИТЬ. В контексте задач, где данные потом группируются и суммируются, это часто является ошибкой производительности.

Поскольку во внешнем запросе у вас стоит СГРУППИРОВАТЬ ПО и СУММА, удаление дублей во вложенном запросе бессмысленно (а иногда и вредно, если две одинаковые суммы должны были сложиться). Для ускорения работы отчета всегда старайтесь использовать ОБЪЕДИНИТЬ ВСЕ.

Итоговый рецепт исправления

Чтобы ваш код работал стабильно на любых версиях платформы (8.2, 8.3) и не вызывал ошибок типизации:

  1. Найдите все поля в секциях ОБЪЕДИНИТЬ, которые заданы как NULL.
  2. Если эти поля в итоге должны суммироваться, замените NULL на 0 или, что еще лучше, на ВЫРАЗИТЬ(NULL КАК ЧИСЛО(...)).
  3. Замените ОБЪЕДИНИТЬ на ОБЪЕДИНИТЬ ВСЕ, если логика не требует строгого удаления дубликатов строк перед суммированием.

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


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

Следуя этим простым правилам, вы избежите ошибок "Неверные параметры" и сделаете ваши запросы более быстрыми и надежными.

← На главную