Почему не считаются итоги в запросе 1С и как это исправить

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

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

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

Причина 1: Использование фигурных скобок в тексте запроса

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


{УПОРЯДОЧИТЬ ПО Док.*, Дата, Номер...}
{ИТОГИ ПО Док.*}

Фигурные скобки {} в языке запросов 1С имеют строго определенное назначение. Они указывают платформе, что данные поля и секции являются необязательными и предназначены для автоматического заполнения механизмами Построителя отчетов или Системы компоновки данных (СКД).

Когда вы выполняете такой запрос напрямую через консоль запросов или в коде с помощью метода Запрос.Выполнить(), платформа полностью игнорирует все, что находится внутри фигурных скобок. В результате секция ИТОГИ просто отбрасывается СУБД, и никаких расчетов не происходит.

Решение: Если вы пишете обычный запрос, который планируете обходить в коде программно (например, через выборку с обходом по группировкам), вам необходимо убрать фигурные скобки и объявить итоги явно:


// Неправильно (для прямого выполнения):
{ИТОГИ ПО Док}

// Правильно:
ИТОГИ ПО Док

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

Причина 2: Попытка рассчитать итоги внутри временной таблицы

Еще одна грубая синтаксическая ошибка в исходном коде — размещение секции итогов внутри пакета запроса, который помещает данные во временную таблицу:


ВЫБРАТЬ
    ...
ПОМЕСТИТЬ ВТПоступления
ИЗ
    Документ.ПоступлениеТоваровУслуг КАК ПоступлениеТоваровУслуг
...
{ИТОГИ ПО Док.*} ;

Если мы уберем фигурные скобки и попытаемся выполнить этот пакет, платформа выдаст ошибку: «Не допускается использование итогов в запросе, результаты которого помещаются во временную таблицу».

Выясним причину этого ограничения. Временная таблица — это физическая таблица, которая создается в базе данных на стороне СУБД (например, в базе tempdb на MS SQL Server). По своей структуре она обязана быть плоской реляционной таблицей. Секция ИТОГИ превращает результат запроса в иерархическую структуру (дерево), содержащую как детальные записи, так и строки итогов по группировкам. Записать такую структуру в плоскую таблицу СУБД невозможно.

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

Причина 3: Не определены агрегатные функции для колонок

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

Если вы напишете просто:

ИТОГИ ПО Док

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

Рассмотрим подробнее, какие функции можно использовать в секции ИТОГИ:

  1. СУММА(Поле) — применяется для числовых показателей (например, количество, сумма, НДС), которые должны складываться на каждом уровне иерархии.
  2. КОЛИЧЕСТВО(Поле) или КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле) — позволяет подсчитать число записей.
  3. МИНИМУМ(Поле) и МАКСИМУМ(Поле) — универсальные агрегатные функции. Они подходят как для чисел, так и для дат или ссылочных типов.

Если вам нужно вывести реквизиты шапки документа (например, Контрагента, Организацию или Договор), которые одинаковы для всех строк внутри одного документа, используйте функцию МАКСИМУМ:


ВЫБРАТЬ
    ВТПоступления.Док КАК Док,
    ВТПоступления.Контрагент КАК Контрагент,
    ВТПоступления.Сумма КАК Сумма
ИЗ
    ВТПоступления КАК ВТПоступления

ИТОГИ 
    МАКСИМУМ(Контрагент), 
    СУММА(Сумма) 
ПО 
    Док

В данном примере на уровне итогов по документу в поле "Контрагент" запишется конкретная ссылка на контрагента (так как для одного документа он уникален), а в поле "Сумма" — общая сумма всех строк этого документа.

Причина 4: Проблема группировки полей неограниченной длины (Комментарий)

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

Попытка написать конструкцию МАКСИМУМ(Комментарий) приведет к ошибке выполнения запроса. Выясним, почему так происходит.

В СУБД (например, MS SQL Server) поля неограниченной длины хранятся как LOB-данные (Large Object) — типы вроде NVARCHAR(MAX) или TEXT. СУБД накладывает жесткие ограничения на работу с такими типами данных: к ним нельзя применять агрегатные функции, их нельзя использовать в условиях группировки СГРУППИРОВАТЬ ПО и по ним невозможно выполнять индексацию или сортировку.

Чтобы обойти это ограничение, нам необходимо привести строку неограниченной длины к строке фиксированной длины. Для этого используется функция ВЫРАЗИТЬ.

Посмотрим на пример правильного преобразования:


ВЫБРАТЬ
    ЗаказПокупателя.Ссылка КАК Ссылка,
    ВЫРАЗИТЬ(ЗаказПокупателя.Комментарий КАК СТРОКА(150)) КАК КомментарийОграниченный,
    ЗаказПокупателя.СуммаДокумента КАК Сумма
ИЗ
    Документ.ЗаказПокупателя КАК ЗаказПокупателя

ИТОГИ 
    МАКСИМУМ(КомментарийОграниченный),
    СУММА(Сумма)
ПО 
    Ссылка

После того как мы явно ограничили длину комментария до 150 символов с помощью функции ВЫРАЗИТЬ, СУБД начинает воспринимать это поле как обычную строку фиксированной длины. Теперь мы без проблем можем использовать к нему функцию МАКСИМУМ в секции итогов.

Важные технические нюансы работы с функцией ВЫРАЗИТЬ

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

Резюме и чек-лист для проверки итогов в запросе

Если у вас в запросе не считаются итоги, выполните проверку по следующему чек-листу:

  1. Убедитесь, что секция ИТОГИ не заключена в фигурные скобки {} (если вы не используете СКД или построитель программно).
  2. Проверьте, что расчет итогов выполняется в самом последнем (финальном) запросе пакета, а не внутри временной таблицы (секции ПОМЕСТИТЬ).
  3. Для всех полей, кроме тех, по которым строятся итоги (секция ПО), обязательно укажите агрегатные функции: СУММА — для чисел, МАКСИМУМ — для ссылок, дат и строк.
  4. Если среди итоговых полей есть реквизиты неограниченной длины (комментарии, описание, адреса), обязательно ограничьте их длину с помощью конструкции ВЫРАЗИТЬ(Поле КАК СТРОКА(Длина)), где длина не превышает 1024 символа.
  5. При тестировании запроса в консоли убедитесь, что вы выбрали режим вывода результата в виде Дерева.
← На главную