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