Как сделать общую группировку и суммирование в объединенном запросе 1С?

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

При разработке отчетов и механизмов сбора данных в 1С разработчики часто сталкиваются с необходимостью объединить данные из нескольких табличных частей разных документов (например, РеализацияТоваровУслуг и ОтчетОРозничныхПродажах) и получить итоговые суммарные показатели по номенклатуре.

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

Почему группировка не сворачивает строки между запросами в ОБЪЕДИНИТЬ ВСЕ?

Проанализируем структуру языка запросов 1С. Когда мы пишем конструкцию вида:


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

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

ВЫБРАТЬ
    Таблица2.Номенклатура,
    СУММА(Таблица2.Количество)
ИЗ
    Документ.ОтчетОРозничныхПродажах.Товары КАК Таблица2
СГРУППИРОВАТЬ ПО
    Таблица2.Номенклатура

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

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

Для получения общего результата необходимо применить один из следующих подходов.

Вариант 1. Использование вложенного запроса

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

Разберем по шагам текст готового запроса:


ВЫБРАТЬ
    Вложенный.Номенклатура КАК Номенклатура,
    СУММА(Вложенный.Количество) КАК Количество
ИЗ
    (ВЫБРАТЬ
        РеализацияТоваровУслугТовары.Номенклатура КАК Номенклатура,
        РеализацияТоваровУслугТовары.Количество КАК Количество
    ИЗ
        Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
    ГДЕ
        РеализацияТоваровУслугТовары.Ссылка.Проведен
        И РеализацияТоваровУслугТовары.Ссылка.Дата МЕЖДУ &ДатаНАЧ И &ДатаОконч
        И РеализацияТоваровУслугТовары.Номенклатура В ИЕРАРХИИ(&Номенклатура)
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
        ОтчетОРозничныхПродажахТовары.Номенклатура КАК Номенклатура,
        ОтчетОРозничныхПродажахТовары.Количество КАК Количество
    ИЗ
        Документ.ОтчетОРозничныхПродажах.Товары КАК ОтчетОРозничныхПродажахТовары
    ГДЕ
        ОтчетОРозничныхПродажахТовары.Ссылка.Проведен
        И ОтчетОРозничныхПродажахТовары.Ссылка.Дата МЕЖДУ &ДатаНАЧ И &ДатаОконч
        И ОтчетОРозничныхПродажахТовары.Номенклатура В ИЕРАРХИИ(&Номенклатура)
        И ОтчетОРозничныхПродажахТовары.Ссылка.Склад В ИЕРАРХИИ(&Склад)) КАК Вложенный

СГРУППИРОВАТЬ ПО
    Вложенный.Номенклатура

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

Вариант 2. Использование пакета запросов и временных таблиц

При работе с объемными выборками или сложной логикой вложенные запросы могут ухудшать план выполнения СУБД. В таких случаях предпочтительнее использовать пакетный запрос с временной таблицей.

Посмотрим на пример организации пакетного запроса:


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

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

ВЫБРАТЬ
    ОтчетОРозничныхПродажахТовары.Номенклатура,
    СУММА(ОтчетОРозничныхПродажахТовары.Количество)
ИЗ
    Документ.ОтчетОРозничныхПродажах.Товары КАК ОтчетОРозничныхПродажахТовары
ГДЕ
    ОтчетОРозничныхПродажахТовары.Ссылка.Проведен
    И ОтчетОРозничныхПродажахТовары.Ссылка.Дата МЕЖДУ &ДатаНАЧ И &ДатаОконч
    И ОтчетОРозничныхПродажахТовары.Номенклатура В ИЕРАРХИИ(&Номенклатура)
    И ОтчетОРозничныхПродажахТовары.Ссылка.Склад В ИЕРАРХИИ(&Склад)
СГРУППИРОВАТЬ ПО
    ОтчетОРозничныхПродажахТовары.Номенклатура
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ.Номенклатура КАК Номенклатура,
    СУММА(ВТ.Количество) КАК Количество
ИЗ
    ВТ_ПродажиДокументы КАК ВТ
СГРУППИРОВАТЬ ПО
    ВТ.Номенклатура

Использование конструкции ПОМЕСТИТЬ позволяет зафиксировать объединенные промежуточные данные в базе, после чего итоговая выборка выполняет чистое суммирование по полям временной таблицы.

Вариант 3. Архитектурно правильное решение — использование регистров накопления

Прямое обращение к табличным частям документов для получения аналитики продаж имеет серьезные недостатки:

  1. Разыменование полей через точку (например, РеализацияТоваровУслугТовары.Ссылка.Проведен или .Ссылка.Дата) приводит к неявным соединениям с таблицами заголовков документов, что при больших объемах снижает производительность.
  2. Документы не содержат предрассчитанных итогов, поэтому СУБД вынуждена сканировать строки таблиц целиком.

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


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

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

Альтернативные способы агрегации данных

Если запрос формируется для отчета или вывода через объектную модель 1С, можно воспользоваться следующими инструментами:

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