При разработке сложных отчетов в системе 1С:Предприятие программисты часто сталкиваются с необходимостью объединения данных из различных источников, например, из регистров накопления и регистров бухгалтерии. Основной инструмент для этого — конструкция ОБЪЕДИНИТЬ ВСЕ. Однако после объединения часто возникает проблема: строки дублируются, а итоги считаются некорректно. В этой статье мы подробно разберем, как правильно группировать поля в таких запросах и эффективно рассчитывать итоги.
Рассмотрим типичную задачу: нам нужно получить данные о плановых обязательствах (из регистра накопления) и фактических расходах (из регистра бухгалтерии) в одном отчете. Автор темы представил следующий работающий, но требующий доработки запрос:
ВЫБРАТЬ
БПФПоОбязательствамОбороты.АБП КАК АБП,
БПФПоОбязательствамОбороты.КлассификацияРасходов.ФКР.Программа КАК ПР,
БПФПоОбязательствамОбороты.КлассификацияРасходов.ФКР.Подпрограмма КАК ППР,
БПФПоОбязательствамОбороты.КлассификацияРасходов.ЭКР КАК СП,
0 КАК СуммаОборот,
(БПФПоОбязательствамОбороты.СуммаЯнварьПриход + БПФПоОбязательствамОбороты.СуммаФевральПриход + ...) КАК СуммаГод
ИЗ
РегистрНакопления.ПланПоБюджетуФинансированияПоОбязательствам.Обороты(...) КАК БПФПоОбязательствамОбороты
ГДЕ Организация = &Организация
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Обязательства.Субконто1.ФКР.АБП КАК АБП,
Обязательства.Субконто1.ФКР.Программа КАК ПР,
Обязательства.Субконто1.ФКР.Подпрограмма КАК ППР,
Обязательства.Субконто1.ЭКР КАК СП,
Обязательства.СуммаОборотКТ КАК СуммаОборот,
0 КАК СуммаГод
ИЗ
РегистрБухгалтерии.Типовой.Обороты(..., Счет = &СчетОбязательств, ..., Организация = &Организация) КАК Обязательства
ИТОГИ
СУММА(СуммаГод), СУММА(СуммаОборот)
ПО АБП, ПР, ППР
Проблема заключается в том, что в результате запроса строки с одинаковыми значениями АБП, ПР и ППР, но разными СП (ЭКР) не схлопываются должным образом, а итоги по детальным записям выглядят избыточными. Выясним причину и найдем решение.
Проанализируем структуру объединения. Чтобы избавиться от повторов на уровне основной выборки, мы можем поместить результат объединения во вложенный запрос и применить к нему СГРУППИРОВАТЬ ПО. Это позволит "схлопнуть" строки с одинаковыми аналитиками еще до расчета итогов.
Рассмотрим, как это выглядит на практике:
ВЫБРАТЬ
Подзапрос.АБП КАК АБП,
Подзапрос.ПР КАК ПР,
Подзапрос.ППР КАК ППР,
Подзапрос.СП КАК СП,
СУММА(Подзапрос.СуммаОборот) КАК СуммаОборот,
СУММА(Подзапрос.СуммаГод) КАК СуммаГод
ИЗ
(
ВЫБРАТЬ АБП, ПР, ППР, СП, 0 КАК СуммаОборот, СуммаГод ИЗ РегистрНакопления...
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ АБП, ПР, ППР, СП, СуммаОборот, 0 КАК СуммаГод ИЗ РегистрБухгалтерии...
) КАК Подзапрос
СГРУППИРОВАТЬ ПО
Подзапрос.АБП,
Подзапрос.ПР,
Подзапрос.ППР,
Подзапрос.СП
Важный момент: использование конструкции ОБЪЕДИНИТЬ ВСЕ вместо просто ОБЪЕДИНИТЬ существенно повышает производительность, так как системе не нужно проверять уникальность каждой строки при слиянии. Группировку мы выполняем позже, что является более оптимальным подходом.
Если ваша цель — не просто убрать дубли, а построить иерархическую структуру отчета, необходимо обратить внимание на секцию ИТОГИ. В исходном запросе автора отсутствовало поле СП в группировках итогов. Это приводило к тому, что система выдавала детальные записи, которые казались "повторяющимися", хотя на самом деле они различались по неучтенному полю.
Разберем правильный вариант написания секции ИТОГИ:
ИТОГИ
СУММА(СуммаГод),
СУММА(СуммаОборот)
ПО
АБП,
ПР,
ППР,
СП // Добавление этого поля решает проблему детализации
Помните: все поля, по которым вы хотите видеть уникальные строки в итоговой выборке, должны быть перечислены в предложении ПО.
Для повышения читаемости и производительности, особенно в сложных запросах 1С, рекомендуется использовать Временные Таблицы (конструкция ПОМЕСТИТЬ). Проанализируем преимущества этого метода:
0 КАК Сумма).Пример использования временной таблицы для нашей задачи:
// Помещаем все данные в одну таблицу
ВЫБРАТЬ
АБП, ПР, ППР, СП, СуммаОборот, СуммаГод
ПОМЕСТИТЬ Вт_Данные
ИЗ
(Здесь наше ОБЪЕДИНИТЬ ВСЕ из первого примера) КАК Вт;
// Выбираем из временной таблицы с группировкой
ВЫБРАТЬ
АБП, ПР, ППР, СП,
СУММА(СуммаОборот) КАК СуммаОборот,
СУММА(СуммаГод) КАК СуммаГод
ИЗ
Вт_Данные КАК Вт_Данные
СГРУППИРОВАТЬ ПО
АБП, ПР, ППР, СП
Проанализируем еще одну частую ошибку, которая присутствовала в исходном коде. Обратите внимание на условие ГДЕ Организация = &Организация. Оно стоит после обращения к виртуальной таблице оборотов.
Рассмотрим подробнее: когда вы ставите условие в секции ГДЕ, 1С сначала выбирает все обороты из базы за период, а затем фильтрует их. Чтобы запрос работал быстрее, условие нужно вносить непосредственно в параметры виртуальной таблицы в скобках:
РегистрНакопления.ПланПоБюджетуФинансированияПоОбязательствам.Обороты(
&НачалоПериода,
&КонецПериода, ,
Организация = &Организация // Фильтр должен быть здесь!
) КАК БПФПоОбязательствамОбороты
Это позволит базе данных отсечь ненужные записи на самом раннем этапе выборки, что критически важно для высоконагруженных систем.
Подводя итог, можно сказать, что группировка в объединенных запросах 1С требует внимательного отношения к набору полей в секциях СГРУППИРОВАТЬ ПО и ИТОГИ. Мы выяснили, что наиболее надежный и производительный способ — это использование ОБЪЕДИНИТЬ ВСЕ внутри временной таблицы с последующей агрегацией данных. Не забывайте также об оптимизации обращений к виртуальным таблицам, чтобы ваши отчеты работали максимально быстро.