При разработке отчетов в 1С программисты часто сталкиваются с ситуацией: в консоли запросов данные отображаются корректно, но при выводе в макет через программный код данные внезапно «исчезают». Особенно часто это происходит, когда в секцию ИТОГИ добавляется ключевое слово ОБЩИЕ. В этой статье мы подробно разберем, почему так происходит, как меняется структура выборки и как правильно изменить алгоритм обхода результата запроса, чтобы все цифры вернулись на свои места.
Когда мы пишем запрос без использования ИТОГИ ПО ОБЩИЕ, метод Выбрать() возвращает нам плоский список или сразу первый уровень указанных группировок. Однако добавление ОБЩИЕ в корень меняет архитектуру результата. Рассмотрим ситуацию: нам нужно посчитать итоги по каждому счету отдельно, а в самом конце вывести общую сумму по всем счетам.
Важный нюанс: как только вы добавляете ОБЩИЕ, в результате запроса появляется «нулевой» уровень — одна единственная строка, содержащая суммарные данные по всему отчету. Теперь все ваши счета и детальные записи находятся «внутри» этой строки. Если ваш старый код просто перебирал выборку в одном цикле Пока Выборка.Следующий(), то теперь он считывает только эту первую итоговую строку и завершает работу, так и не дойдя до самих счетов. Именно это создает иллюзию «исчезновения» данных.
Для того чтобы вывести данные в макет, когда в запросе есть и общие итоги, и итоги по группировкам, нам необходимо использовать вложенные циклы. Разберем по шагам, как должен выглядеть код обработки результата запроса.
Сначала мы получаем общую выборку. Поскольку мы указали ИТОГИ ПО ОБЩИЕ, первой строкой пойдет общий итог. Чтобы «провалиться» глубже к счетам, нам нужно вызвать метод Выбрать повторно от текущей выборки.
// 1. Получаем результат запроса
РезультатЗапроса = Запрос.Выполнить();
// 2. Выборка самого верхнего уровня (Общие итоги)
ВыборкаОбщийИтог = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаОбщийИтог.Следующий() Цикл
// Здесь выводим строку с общими итогами в макет, если нужно
ОбластьИтог.Параметры.Заполнить(ВыборкаОбщийИтог);
ТабДок.Вывести(ОбластьИтог);
// 3. Переходим на уровень ниже — к группировке "Счет"
ВыборкаСчет = ВыборкаОбщийИтог.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Счет");
Пока ВыборкаСчет.Следующий() Цикл
// Выводим итоги по конкретному счету
ОбластьСчет.Параметры.Заполнить(ВыборкаСчет);
ТабДок.Вывести(ОбластьСчет);
// 4. Если нужны детальные записи (статьи ДДС), спускаемся еще глубже
ВыборкаДетали = ВыборкаСчет.Выбрать();
Пока ВыборкаДетали.Следующий() Цикл
ОбластьСтрока.Параметры.Заполнить(ВыборкаДетали);
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
КонецЦикла;
КонецЦикла;
Обратите внимание на использование параметра ОбходРезультатаЗапроса.ПоГруппировкам. Именно он заставляет систему соблюдать вложенность, которую мы описали в тексте запроса в секции ИТОГИ.
Для корректной работы итогов и высокой производительности, особенно в бухгалтерских отчетах, проанализируем сам текст запроса. Использование условий через ИЛИ (как в примере Счет = &Счет1 ИЛИ Счет = &Счет2) внутри виртуальных таблиц может замедлять работу базы данных.
Рекомендуем передавать список счетов массивом. Это позволяет СУБД строить более эффективный план запроса. Также важно использовать АВТОУПОРЯДОЧИВАНИЕ, чтобы система правильно выстроила иерархию при обходе.
Рассмотрим улучшенный вариант запроса:
ВЫБРАТЬ
ХозрасчетныйОстаткиИОбороты.Счет КАК Счет,
ВЫБОР
КОГДА ХозрасчетныйОстаткиИОбороты.Счет = &Счет5001 ТОГДА ХозрасчетныйОстаткиИОбороты.Субконто1
ИНАЧЕ ХозрасчетныйОстаткиИОбороты.Субконто2
КОНЕЦ КАК СтатьяДДС,
СУММА(ХозрасчетныйОстаткиИОбороты.СуммаНачальныйОстаток) КАК ОстатокНаНачало,
СУММА(ХозрасчетныйОстаткиИОбороты.СуммаОборотДт) КАК СуммаОборотДт,
СУММА(ХозрасчетныйОстаткиИОбороты.СуммаОборотКт) КАК СуммаОборотКт,
СУММА(ХозрасчетныйОстаткиИОбороты.СуммаКонечныйОстаток) КАК СуммаКонечныйОстаток
ИЗ
РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&НачПериода, &КонПериода, , , Счет В (&МассивСчетов), , ) КАК ХозрасчетныйОстаткиИОбороты
СГРУППИРОВАТЬ ПО
Счет,
ВЫБОР
КОГДА ХозрасчетныйОстаткиИОбороты.Счет = &Счет5001 ТОГДА ХозрасчетныйОстаткиИОбороты.Субконто1
ИНАЧЕ ХозрасчетныйОстаткиИОбороты.Субконто2
КОНЕЦ
УПОРЯДОЧИТЬ ПО
Счет
ИТОГИ
СУММА(ОстатокНаНачало),
СУММА(СуммаОборотДт),
СУММА(СуммаОборотКт),
СУММА(СуммаКонечныйОстаток)
ПО
ОБЩИЕ,
Счет
АВТОУПОРЯДОЧИВАНИЕ
Проанализируем важный технический момент: суммирование ресурсов типа «Остаток». В обычных запросах 1С при использовании СУММА() в итогах остатки могут суммироваться некорректно, если данные задублированы по разным аналитикам (субконто). Система просто сложит все цифры, что приведет к завышению итогового остатка.
Если вы столкнулись с тем, что «Общий итог» по остаткам не сходится с реальным сальдо, выясним причину. В идеале для таких отчетов стоит использовать Систему компоновки данных (СКД). Она умеет правильно работать с ролями полей (Начальный остаток / Конечный остаток) и рассчитывает итоги по ним по специальным правилам бухгалтерского учета, а не простым сложением всех строк.
Если задача позволяет, рассмотрите переход с ручного формирования макета на СКД. Это избавит вас от необходимости писать вложенные циклы Выбрать(). Система компоновки данных:
NULL в значениях субконто.Таким образом, «исчезновение» данных — это не ошибка платформы, а следствие изменения структуры выборки. Используя вложенный обход группировок или перейдя на СКД, вы обеспечите корректное отображение всех уровней итогов в вашем отчете.