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

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

Как в 1С сгруппировать объединённые запросы

Как в запросе 1С сгруппировать данные из нескольких таблиц, объединённых через ОБЪЕДИНИТЬ ВСЕ: вложенные запросы, агрегаты, типичные ошибки, примеры кода.

Задача сгруппировать данные, собранные из нескольких запросов через ОБЪЕДИНИТЬ, возникает постоянно: продажи и возвраты, приходы и расходы, документы разных видов. Проблема в том, что конструкция СГРУППИРОВАТЬ ПО применяется к каждому подзапросу отдельно, а не ко всему объединённому набору. Из-за этого новички получают дубли строк вместо свёрнутых итогов.

Правильное решение — обернуть объединение во вложенный запрос и группировать уже его результат во внешнем запросе. Так язык запросов 1С сначала склеит все строки в единый набор, а затем агрегирует их по нужным измерениям. Ниже разобраны рабочие примеры, ограничения конструктора и типичные ошибки.

Почему группировка не работает напрямую после ОБЪЕДИНИТЬ

В языке запросов 1С предложение СГРУППИРОВАТЬ ПО синтаксически относится к тому подзапросу, внутри которого оно написано. Когда вы пишете ОБЪЕДИНИТЬ ВСЕ между двумя выборками, платформа воспринимает их как независимые части: каждая со своим ВЫБРАТЬ, ИЗ, ГДЕ и СГРУППИРОВАТЬ ПО. Общей группировки «поверх» объединения в синтаксисе просто нет.

Если добавить СГРУППИРОВАТЬ ПО в каждый подзапрос, вы сгруппируете строки внутри каждой части отдельно. Но одинаковые ключи из разных частей (например, один контрагент в продажах и в возвратах) останутся разными строками результата. Именно это чаще всего выглядит как «группировка не работает».

Выход — двухуровневая структура: внутренний запрос собирает плоский набор строк через ОБЪЕДИНИТЬ ВСЕ, внешний — группирует его. Платформа выполнит сначала внутреннюю часть, материализует её и только потом применит агрегацию.

Базовый пример: продажи и возвраты одной группировкой

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

ВЫБРАТЬ

Данные.Контрагент КАК Контрагент,

СУММА(Данные.СуммаПродажи) КАК СуммаПродажи,

СУММА(Данные.СуммаВозврата) КАК СуммаВозврата

ИЗ

(ВЫБРАТЬ

Продажи.Контрагент КАК Контрагент,

Продажи.Сумма КАК СуммаПродажи,

0 КАК СуммаВозврата

ИЗ

РегистрНакопления.Продажи.Обороты(, , , ) КАК Продажи

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ

Возвраты.Контрагент,

0,

Возвраты.Сумма

ИЗ

РегистрНакопления.Продажи.Обороты(, , , ) КАК Возвраты) КАК Данные

СГРУППИРОВАТЬ ПО

Данные.Контрагент

Обратите внимание на приём с нулевыми колонками: в каждом подзапросе поле, которого нет в источнике, заполняется нулём. Тогда во внешней группировке СУММА корректно посчитает каждый показатель отдельно, и не понадобятся левые соединения с обработкой NULL.

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

Порядок построения запроса
  1. 1
    Напишите первый подзапрос: ВЫБРАТЬ поля измерений и показателей из первого источника
  2. 2
    Добавьте ОБЪЕДИНИТЬ ВСЕ и второй подзапрос с тем же набором полей по количеству и типам
  3. 3
    Заключите всё объединение в скобки и дайте ему псевдоним, например КАК Данные
  4. 4
    Во внешнем запросе выберите поля через Данные.ИмяПоля, примените СУММА и другие агрегаты
  5. 5
    Добавьте СГРУППИРОВАТЬ ПО по полям измерений и проверьте результат в консоли запросов

Группировка в конструкторе запроса

Конструктор запросов в конфигураторе умеет строить такую структуру, но с оговорками. На закладке «Объединения/Псевдонимы» вы добавляете подзапросы объединения, а вкладка «Группировка» работает только для текущего редактируемого запроса. Чтобы сгруппировать объединённый набор, нужно создать вложенный запрос: правой кнопкой по полю источника — «Добавить вложенный запрос» либо через замену таблицы на вложенный запрос.

Практический путь: сначала соберите объединение как отдельный запрос, проверьте его, затем превратите его во вложенный и во внешнем запросе перетащите нужные поля на закладку «Группировка» — измерения в группировочные поля, показатели в суммируемые. Конструктор сам проставит СУММА и СГРУППИРОВАТЬ ПО.

Если конструктор запутывает структуру (такое бывает при нескольких уровнях вложенности), проще отредактировать текст вручную: кнопка «Запрос» открывает текстовый режим. Ручная правка не мешает потом снова открыть конструктор, если синтаксис корректен.

Группировка с условиями, итогами и разными типами полей

Отбор лучше накладывать внутри каждого подзапроса объединения через ГДЕ, а не во внешнем запросе: так СУБД отфильтрует данные до склейки, и объём обрабатываемых строк будет меньше. Условие на уже сгруппированные значения (например, сумма больше порога) выносите во внешний запрос через ИМЕЮЩИЕ.

Для аналитики по иерархии добавьте во внешний запрос ИТОГИ ПО — это даст промежуточные итоги без дополнительных объединений. Например, сгруппировать по контрагенту и номенклатуре, а итоги посчитать по контрагенту.

Следите за приведением типов. Если в одном подзапросе поле ссылочного типа, а в другом — строка или NULL, объединённое поле получит составной тип, и группировка по нему может вести себя неожиданно: строки с NULL не сольются со ссылками. Явно приводите значения через ВЫРАЗИТЬ или ЕСТЬ NULL ещё во вложенном запросе.

Альтернативы: временные таблицы и СКД

Если объединение большое или используется в нескольких местах одного пакетного запроса, удобнее поместить его во временную таблицу (ПОМЕСТИТЬ), а затем группировать уже её. Это упрощает текст, позволяет проиндексировать поля соединения и ускоряет отладку — каждый этап проверяется отдельно в консоли запросов.

В отчётах на СКД часто вообще не нужна группировка в тексте запроса: достаточно выбрать детальные строки объединения, а группировку выполнит сама компоновка по настройкам отчёта. Ресурсы с агрегатом Сумма на закладке «Ресурсы» свернут данные на уровне СКД.

Способы сгруппировать объединённые данные

Вложенный запрос + СГРУППИРОВАТЬ ПО

Универсальный вариант для кода и консоли. Минус — многоуровневый текст, сложнее читать при 3+ источниках.

Временная таблица + группировка

Удобно при повторном использовании набора и для отладки. Требует менеджера временных таблиц.

Группировка средствами СКД

Лучший вариант для отчётов: запрос проще, группировки настраиваются пользователем. Не подходит для запросов в коде, где нужен готовый свёрнутый результат.

Как проверить результат и типичные ошибки

Проверка строится на контрольных суммах. Выполните внутреннее объединение без группировки и посчитайте сумму показателя вручную или через СУММА без группировочных полей — она должна совпасть с общей суммой сгруппированного результата. Расхождение означает потерю строк: чаще всего из-за ОБЪЕДИНИТЬ без ВСЕ или отбора, отрезающего часть данных.

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

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

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

Общая сумма показателя
Норма

Совпадает с суммой по негруппированному объединению

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

Меньше — потеряны строки, проверьте ВСЕ и отборы

Строки по одному ключу
Норма

Одна строка на уникальную комбинацию полей группировки

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

Дубли ключей — группировка не на внешнем уровне

Поле группировки
Норма

Нет пустых/NULL значений, если их не должно быть

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

NULL-строка собрала часть данных — приведите типы через ЕСТЬ NULL

Итог

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

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

Частые вопросы

Можно ли написать СГРУППИРОВАТЬ ПО сразу после ОБЪЕДИНИТЬ без вложенного запроса?

Нет, синтаксис языка запросов 1С этого не позволяет: группировка относится только к своему подзапросу. Единственный способ — обернуть объединение во вложенный запрос или временную таблицу и группировать его результат во внешней выборке.

Чем ОБЪЕДИНИТЬ отличается от ОБЪЕДИНИТЬ ВСЕ при группировке?

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

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

Обычно это NULL, попавший во вложенный запрос — например, из левого соединения или несовпадения типов полей в частях объединения. Обработайте значения функцией ЕСТЬ NULL во вложенном запросе либо отфильтруйте их условием ГДЕ.

Как отфильтровать сгруппированный результат по сумме?

Используйте предложение ИМЕЮЩИЕ во внешнем запросе, например: ИМЕЮЩИЕ СУММА(Данные.Сумма) > 10000. Условие ГДЕ для агрегатов не подходит — оно применяется до группировки и не видит итоговых значений.

Что лучше для отчёта: группировка в запросе или настройки СКД?

Для отчётов на СКД предпочтительнее оставить в запросе детальные строки объединения, а группировку и ресурсы настроить в компоновке. Запрос получится проще, а пользователь сможет менять структуру отчёта без доработки кода.

Можно ли группировать объединение из трёх и более подзапросов?

Да, количество частей ОБЪЕДИНИТЬ ВСЕ не ограничивает внешнюю группировку — внешний запрос работает с объединённым набором как с единой таблицей. Важно лишь, чтобы все части возвращали одинаковый набор полей с совместимыми типами.