К статье
Практический материал

Разработка и Конфигурация · 10 мин

Сумма и ГДЕ в запросах 1С: считаем итоги с условием

Как использовать СУММА вместе с ГДЕ в языке запросов 1С: синтаксис, примеры кода, типичные ошибки с группировкой, NULL и проверка результата.

Запрос «сумма в где 1С» обычно означает одну из двух задач: посчитать итог по полю с помощью агрегатной функции СУММА или отфильтровать данные условием ГДЕ перед суммированием. В языке запросов 1С эти конструкции работают вместе, но у них есть важное ограничение: ГДЕ применяется к строкам до группировки, а условие на уже посчитанную сумму задаётся через ИМЕЮЩИЕ.

Ниже разобран синтаксис СУММА и ГДЕ, порядок выполнения секций запроса, примеры для типовых задач (обороты по контрагенту, остатки по складу, отбор документов по сумме) и ошибки, из-за которых итог получается неверным или запрос падает с ошибкой.

Как устроены СУММА и ГДЕ в языке запросов 1С

Язык запросов 1С построен по образцу SQL, но со своими особенностями. Секция ГДЕ задаёт условие отбора строк из виртуальной таблицы или регистра: сначала отбираются записи, потом они группируются, и только затем вычисляется СУММА. Поэтому в ГДЕ нельзя ссылаться на агрегатную функцию — на момент отбора суммы ещё не существует.

Для условия по результату агрегации предусмотрена секция ИМЕЮЩИЕ (аналог HAVING). Типовая ошибка новичка — написать ГДЕ СУММА(Оборот) > 100000 и получить сообщение об ошибке «Агрегатная функция не может использоваться в данном выражении».

Базовый пример: сумма с условием отбора

Классическая задача — посчитать сумму продаж по конкретному контрагенту за период. Условие по контрагенту и датам задаётся в ГДЕ, суммирование — через СУММА с группировкой или без неё.

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

Обратите внимание: параметры виртуальной таблицы (период, отбор) лучше передавать в скобках самой таблицы, а не в секции ГДЕ. Это быстрее, потому что отбор выполняется на уровне виртуальной таблицы до соединения с остальными данными. Условие в ГДЕ оставляйте для полей, которые нельзя вынести в параметры.

Если группировка не нужна (требуется одна итоговая сумма), секцию СГРУППИРОВАТЬ ПО можно опустить — запрос вернёт одну строку с итогом по всем отобранным записям.

Фильтрация по сумме: секция ИМЕЮЩИЕ

Когда нужно оставить только те группы, где сумма превышает порог, — например, контрагенты с оборотом больше заданного значения, — условие пишется в ИМЕЮЩИЕ после группировки.

bsl
ВЫБРАТЬ
	Продажи.Контрагент КАК Контрагент,
	СУММА(Продажи.СуммаОборот) КАК Оборот
ИЗ
	РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Продажи
СГРУППИРОВАТЬ ПО
	Продажи.Контрагент
ИМЕЮЩИЕ
	СУММА(Продажи.СуммаОборот) > &МинимальныйОборот

В ИМЕЮЩИЕ допустимо комбинировать условия: по сумме, по количеству записей (КОЛИЧЕСТВО), по максимуму. Логические операторы И, ИЛИ, НЕ работают так же, как в ГДЕ. Порядок секций фиксирован: ВЫБРАТЬ → ИЗ → ГДЕ → СГРУППИРОВАТЬ ПО → ИМЕЮЩИЕ → УПОРЯДОЧИТЬ ПО.

Сумма по условию внутри одного поля: ВЫБОР КОГДА

Частая задача — в одной строке получить несколько сумм по разным условиям: например, отдельно приход и расход, отдельно оплаченные и неоплаченные документы. Здесь ГДЕ не подходит, потому что он отсекает строки целиком. Вместо этого условие переносится внутрь агрегатной функции через конструкцию ВЫБОР КОГДА.

bsl
ВЫБРАТЬ
	Расчёты.Контрагент КАК Контрагент,
	СУММА(ВЫБОР
		КОГДА Расчёты.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
			ТОГДА Расчёты.Сумма
		ИНАЧЕ 0
	КОНЕЦ) КАК Приход,
	СУММА(ВЫБОР
		КОГДА Расчёты.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Расход)
			ТОГДА Расчёты.Сумма
		ИНАЧЕ 0
	КОНЕЦ) КАК Расход
ИЗ
	РегистрНакопления.РасчётыСКонтрагентами КАК Расчёты
СГРУППИРОВАТЬ ПО
	Расчёты.Контрагент

Такой приём называют условным агрегированием. Он выполняется за один проход по таблице и обычно быстрее, чем два отдельных запроса с разными условиями в ГДЕ и последующее соединение результатов.

Типичные ошибки при работе с СУММА и ГДЕ

Первая группа ошибок — синтаксические: попытка использовать СУММА в секции ГДЕ, пропущенная группировка по неагрегированному полю, неверный порядок секций. Платформа выдаёт сообщение об ошибке при построении запроса, и такие проблемы обнаруживаются сразу.

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

Типичные ошибки
01
Условие по сумме написано в ГДЕ вместо ИМЕЮЩИЕ — запрос не выполняется с ошибкой об агрегатной функции.
02
Соединение детальных таблиц до группировки — суммы умножаются на количество совпавших строк второй таблицы.
03
В ИНАЧЕ конструкции ВЫБОР КОГДА стоит NULL — итог по группе становится NULL вместо 0.
04
Отбор по периоду написан в ГДЕ вместо параметров виртуальной таблицы — запрос работает медленнее на больших объёмах.
05
Поле добавлено в ВЫБРАТЬ, но не добавлено в СГРУППИРОВАТЬ ПО и не обёрнуто в агрегат — ошибка построения запроса.

Производительность: где ставить условия

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

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

Где задавать условие

Параметры виртуальной таблицы

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

Секция ГДЕ

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

Секция ИМЕЮЩИЕ

Единственный способ отфильтровать по значению СУММА, КОЛИЧЕСТВО и других агрегатов. Применяется после группировки, поэтому не сокращает объём обрабатываемых строк.

ВЫБОР КОГДА внутри СУММА

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

Как проверить, что сумма посчитана правильно

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

Полезный приём — выполнить тот же запрос без группировки и СУММА, вывести детальные строки и просуммировать их вручную по одной группе. Так видно, какие именно записи попали в выборку и не задвоились ли они из-за соединения.

Контрольные точки

Как проверить результат

Сумма по одной группе
Норма

Совпадает с типовым отчётом или ручным сложением детальных строк

Тревожный признак

Кратно больше ожидаемой — вероятно задвоение из-за соединения до группировки

Пустые группы
Норма

Группы без движений либо отсутствуют, либо дают 0

Тревожный признак

В поле суммы NULL — мешает дальнейшим вычислениям

Границы периода
Норма

Документы на конечную дату включены (используйте конец дня или границу)

Тревожный признак

Документы последнего дня теряются — период задан без учёта времени

Скорость выполнения
Норма

Запрос по виртуальной таблице выполняется быстро даже на большом регистре

Тревожный признак

Запрос суммирует физическую таблицу движений и заметно тормозит

Выполнение запроса из кода и получение суммы

В модуле запрос создаётся объектом Запрос, параметры устанавливаются методом УстановитьПараметр, результат получают через Выполнить().Выбрать() или Выгрузить(). Если запрос возвращает одну строку с итогом, удобно сразу обработать ситуацию пустого результата — когда по условию ГДЕ не нашлось ни одной записи, выборка будет пустой, и обращение к полю без проверки вызовет ошибку.

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

FAQ

Можно ли использовать СУММА в секции ГДЕ?

Нет. Секция ГДЕ выполняется до группировки, когда агрегатные значения ещё не вычислены. Условие по сумме пишите в секции ИМЕЮЩИЕ после СГРУППИРОВАТЬ ПО.

Почему СУММА вернула NULL вместо числа?

Агрегат по пустому набору строк или по строкам, где поле равно NULL, даёт NULL. Обрабатывайте это в коде через проверку на NULL или используйте ЕСТЬNULL(СУММА(Поле), 0) в тексте запроса.

Как посчитать сумму только по проведённым документам?

Если данные берутся из регистра, непроведённые документы туда не пишут движения — дополнительное условие не нужно. Если суммируете реквизиты самих документов, добавьте в ГДЕ условие Документ.Проведен = ИСТИНА.

Почему сумма в запросе больше, чем в типовом отчёте?

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

Как получить сумму без группировки по измерениям?

Просто не указывайте СГРУППИРОВАТЬ ПО и не выбирайте неагрегированные поля. Запрос вида ВЫБРАТЬ СУММА(Поле) ИЗ ... ГДЕ ... вернёт одну строку с общим итогом по отобранным записям.

Что быстрее: СУММА по физической таблице или виртуальная таблица Обороты?

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

Итог

Что важно запомнить

ГДЕ отбирает строки до суммирования, ИМЕЮЩИЕ фильтрует по готовой сумме, ВЫБОР КОГДА внутри СУММА даёт несколько условных итогов в одной строке. Отборы по периоду и измерениям выносите в параметры виртуальной таблицы, соединяйте таблицы после группировки, а результат всегда сверяйте с типовым отчётом.