При работе с языком запросов 1С:Предприятие 8 разработчики часто сталкиваются с ситуацией, когда при попытке настроить группировку в Конструкторе запроса на закладке «Группировки» для определенного поля в списке доступных агрегатных функций отображается только КОЛИЧЕСТВО или КОЛИЧЕСТВО РАЗЛИЧНЫЕ. При этом ожидаемая функция СУММА просто отсутствует в списке. Разберем детально, почему это происходит, как система определяет типы данных и каким образом можно гарантированно получить возможность суммирования значений.
Рассмотрим типичный пример кода, который приводит к подобному поведению системы. Проблема часто кроется во вложенных запросах, где вычисляются флаги или количественные показатели на основе условий. Проанализируем фрагмент кода из вложенного запроса:
ВЫБОР
КОГДА МойДок.Операция = ЗНАЧЕНИЕ(Перечисление.МоеПеречисление.КакоеТоЗначение1)
ТОГДА "1"
ИНАЧЕ "0"
КОНЕЦ КАК КоличествоПроданных
В данном примере разработчик совершает критическую ошибку — заключает цифры 1 и 0 в двойные кавычки. В языке запросов 1С текст в кавычках (например, "1") всегда воспринимается системой как Строка. Агрегатная функция СУММА математически определена только для числовых типов данных. Поскольку поле КоличествоПроданных на выходе из вложенного запроса имеет тип Строка, конструктор запроса логично предлагает только те функции, которые применимы к строкам: подсчет количества записей или выбор уникальных значений.
Важно понимать внутреннюю логику работы платформы при расчете типов в конструкции ВЫБОР. Рассмотрим правила, по которым 1С определяет, какой тип данных будет у итоговой колонки:
ВЫБОР во многом определяется по первому значению, указанному после ключевого слова ТОГДА. Если там стоит строка, вся колонка будет типизирована как строковая.ТОГДА возвращаются значения разных типов (например, число и строка), система попытается привести их к составному типу или возникнет ошибка при выполнении, если типы несовместимы.1, 0, 100.5). Использование кавычек превращает число в текст, лишая его математических свойств.Для исправления ситуации из примера выше необходимо изменить код, убрав кавычки у литералов:
ВЫБОР
КОГДА МойДок.Операция = ЗНАЧЕНИЕ(Перечисление.МоеПеречисление.КакоеТоЗначение1)
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ КАК КоличествоПроданных
После такого изменения поле КоличествоПроданных получит тип Число, и в конструкторе запроса на верхнем уровне станет доступна функция СУММА.
Иногда возникают более сложные ситуации, когда тип поля во вложенном запросе не очевиден для конструктора запроса (например, если поле получается в результате сложного соединения таблиц или из параметров). В таких случаях мы можем использовать функцию ВЫРАЗИТЬ, чтобы «подсказать» системе нужный тип данных. Проанализируем следующий пример:
ВЫБРАТЬ
ВложенныйЗапрос.Ссылка,
СУММА(ВЫРАЗИТЬ(ВложенныйЗапрос.Поле КАК ЧИСЛО(15, 2))) КАК ИтоговаяСумма
ИЗ
(...) КАК ВложенныйЗапрос
ГРУППИРОВАТЬ ПО
ВложенныйЗапрос.Ссылка
Однако следует помнить важное ограничение: функция ВЫРАЗИТЬ в запросах 1С не умеет конвертировать типы «на лету», как это делают функции приведения типов в некоторых языках программирования. Она не может превратить строку "123" в число 123. Эта функция предназначена для ограничения длины строк или точности чисел, а также для работы с составными типами данных (приведение к конкретной ссылке).
Разберем ситуацию, которая часто возникает при использовании ЛЕВОЕ СОЕДИНЕНИЕ. Если мы суммируем числовое поле из правой таблицы, которое может содержать NULL, функция СУММА корректно обработает эти записи (она их просто проигнорирует). Однако, если результатом суммирования по всей группе окажется только набор из NULL, результатом будет NULL. Это может привести к ошибкам в коде при попытке обращения к результату запроса.
Рекомендуется использовать конструкцию ЕСТЬNULL для обеспечения корректности данных:
ВЫБРАТЬ
Продажи.Номенклатура,
ЕСТЬNULL(СУММА(Продажи.Количество), 0) КАК ВсегоПродано
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ
РегистрНакопления.Продажи КАК Продажи
ПО
Номенклатура.Ссылка = Продажи.Номенклатура
ГРУППИРОВАТЬ ПО
Продажи.Номенклатура
При работе с группировками и сложными вычислениями типов важно затронуть вопрос производительности. Выясним причину, по которой использование временных таблиц предпочтительнее вложенных запросов. Когда мы создаем временную таблицу, типы полей фиксируются в схеме базы данных более жестко. Это помогает оптимизатору СУБД строить более эффективные планы запросов.
Рассмотрим, как можно переписать запрос с использованием временной таблицы для повышения читаемости и надежности типизации:
// Шаг 1: Подготовка данных во временную таблицу
ВЫБРАТЬ
МойДок.Ссылка КАК Ссылка,
ВЫБОР
КОГДА МойДок.Операция = ЗНАЧЕНИЕ(Перечисление.МоеПеречисление.Значение1) ТОГДА 1
ИНАЧЕ 0
КОНЕЦ КАК КоличествоЧислом
ПОМЕСТИТЬ ВТ_ПодготовленныеДанные
ИЗ
Документ.МойДок КАК МойДок;
// Шаг 2: Финальная группировка
ВЫБРАТЬ
ВТ.Ссылка,
СУММА(ВТ.КоличествоЧислом) КАК Итого
ИЗ
ВТ_ПодготовленныеДанные КАК ВТ
ГРУППИРОВАТЬ ПО
ВТ.Ссылка
Преимущества такого подхода:
КоличествоЧислом будет однозначно определен как числовой при создании временной таблицы.Многие начинающие разработчики считают, что отсутствие функции СУММА в конструкторе — это ошибка самой программы 1С. На самом деле, это продуманный механизм защиты. Конструктор запроса анализирует метаданные и структуру выражения. Если он видит, что на вход группировки поступает строковый тип, он блокирует возможность выбора функции СУММА, чтобы предотвратить создание синтаксически неверного SQL-запроса, который СУБД (будь то MS SQL Server, PostgreSQL или Oracle) не сможет выполнить. Строки нельзя складывать арифметически — это фундаментальное ограничение реляционных баз данных.
Если вы обнаружили, что в вашем запросе недоступно суммирование, выполните следующие шаги для локализации и решения проблемы:
ВЫБОР. Если они есть — удалите их.ВЫБОР возвращают значения одного и того же (числового) типа.ЛЕВОЕ СОЕДИНЕНИЕ не забывайте про обработку NULL через ЕСТЬNULL.Соблюдение этих простых правил типизации позволит вам эффективно работать с агрегатными функциями и избегать ошибок при проектировании сложных аналитических отчетов в системе 1С:Предприятие 8.