При разработке отчетов и обработок в платформе 1С часто возникает задача: вывести количество документов по каждому ответственному менеджеру и одновременно получить итоговое (общее) количество документов за указанный период.
Сложность заключается в том, что в языке запросов 1С отсутствуют оконные (аналитические) функции вроде OVER(), которые в классических СУБД позволяют выводить общее значение агрегата в каждой строке сгруппированного запроса. Рассмотрим подробнее основные способы решения этой задачи в зависимости от ваших целей.
Если запрос выполняется непосредственно из кода 1С для последующей обработки выборки или вывода в документ, наиболее простым решением является применение конструкции ИТОГИ ПО ОБЩИЕ.
Проанализируем пример такого запроса:
ВЫБРАТЬ
ЗаказКлиента.Менеджер КАК Менеджер,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ЗаказКлиента.Ссылка) КАК КоличествоЗаказов
ИЗ
Документ.ЗаказКлиента КАК ЗаказКлиента
ГДЕ
ЗаказКлиента.Дата МЕЖДУ &НачДата И &КонДата
СГРУППИРОВАТЬ ПО
ЗаказКлиента.Менеджер
ИТОГИ
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ КоличествоЗаказов)
ПО
ОБЩИЕ,
Менеджер
Особенности данного подхода:
ИТОГИ ПО ОБЩИЕ создает специальную итоговую запись на верхнем уровне результата запроса.ВыборкаИзРезультатаЗапроса вы сможете сначала получить общую сумму по всем документам, а затем детально обойти строки по менеджерам.ИТОГИ нельзя поместить во временную таблицу (с помощью ключевого слова ПОМЕСТИТЬ) или использовать во вложенных запросах пакета.Если вам требуется добавить поле с общим количеством документов к каждой строке сгруппированного результата (например, для последующего соединения с другими таблицами в пакете запросов), разберем по шагам правильную структуру пакетного запроса.
Сначала сформируем временную таблицу, рассчитав общее количество уникальных документов с учетом отборов по дате:
ВЫБРАТЬ
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ЗаказКлиента.Ссылка) КАК ОбщийИтогДокументов
ПОМЕСТИТЬ ВТ_ОбщийИтог
ИЗ
Документ.ЗаказКлиента КАК ЗаказКлиента
ГДЕ
ЗаказКлиента.Дата МЕЖДУ &НачДата И &КонДата
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ЗаказКлиента.Менеджер КАК Менеджер,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ЗаказКлиента.Ссылка) КАК КоличествоЗаказовМенеджера,
ВТ_ОбщийИтог.ОбщийИтогДокументов КАК ВсегоДокументов
ИЗ
Документ.ЗаказКлиента КАК ЗаказКлиента
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ОбщийИтог КАК ВТ_ОбщийИтог
ПО ИСТИНА
ГДЕ
ЗаказКлиента.Дата МЕЖДУ &НачДата И &КонДата
СГРУППИРОВАТЬ ПО
ЗаказКлиента.Менеджер,
ВТ_ОбщийИтог.ОбщийИтогДокументов
Рассмотрим, как работает данная схема:
ОбщийИтогДокументов и помещает её в ВТ_ОбщийИтог.ВТ_ОбщийИтог присоединяется по условию ПО ИСТИНА (без указания ключевых полей связи). Это позволяет добавить итоговое число в каждую строчку результата.В случаях, когда дублировать общий итог в каждой строчке выборки не требуется, а нужно получить два независимых результата в одном обращении к СУБД, используем метод ВыполнитьПакет() объекта Запрос.
Посмотрим на пример структуры пакета:
ВЫБРАТЬ
ЗаказКлиента.Менеджер КАК Менеджер,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ЗаказКлиента.Ссылка) КАК КоличествоЗаказов
ИЗ
Документ.ЗаказКлиента КАК ЗаказКлиента
ГДЕ
ЗаказКлиента.Дата МЕЖДУ &НачДата И &КонДата
СГРУППИРОВАТЬ ПО
ЗаказКлиента.Менеджер
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ЗаказКлиента.Ссылка) КАК ВсегоДокументов
ИЗ
Документ.ЗаказКлиента КАК ЗаказКлиента
ГДЕ
ЗаказКлиента.Дата МЕЖДУ &НачДата И &КонДата
В коде модуля 1С обработка результатов выполняется следующим образом:
РезультатыПакет = Запрос.ВыполнитьПакет();
// Выборка по менеджерам
ВыборкаМенеджеры = РезультатыПакет[0].Выбрать();
Пока ВыборкаМенеджеры.Следующий() Цикл
// Обработка строк по менеджерам
КонецЦикла;
// Получение общего количества
ВыборкаИтог = РезультатыПакет[1].Выбрать();
Если ВыборкаИтог.Следующий() Тогда
ОбщееКоличество = ВыборкаИтог.ВсегоДокументов;
КонецЕсли;
ГДЕ (период, проведения, пометки удаления и т.д.) должны совпадать во всех запросах пакета. Если в основном запросе добавить дополнительный фильтр, а в расчете общего итога его пропустить, итоговые данные рассинхронизируются.КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка) вместо КОЛИЧЕСТВО(*), если в запросе присутствуют соединения с табличными частями или другими детальными таблицами, чтобы избежать завышения показателей из-за дублирования ссылок.