При переходе на новые релизы платформы 1С:Предприятие 8.3.27 многие разработчики столкнулись с неприятной особенностью: отчеты, которые годами работали корректно, начинают показывать неверные данные в колонках начальных и конечных остатков. Особенно часто это проявляется в конфигурациях на обычных формах (например, УТ 10.3), но проблема актуальна для любой конфигурации, использующей Систему компоновки данных (СКД). Разберем подробно, почему это происходит и как вернуть корректные цифры в отчеты.
Рассмотрим типичную ситуацию. В СКД используется запрос к виртуальной таблице РегистрНакопления.ПартииТоваровНаСкладах.ОстаткиИОбороты. Пока в настройках отчета (на вкладке "Выбранные поля") присутствуют все вспомогательные поля или расчетные величины, данные выводятся верно. Однако стоит пользователю убрать "лишнее", по его мнению, поле (например, расчет количества дней в периоде), как начальные и конечные остатки начинают суммироваться арифметически, превращаясь в бессмысленные значения.
Проанализируем исходный запрос, который вызывает проблему:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
НАЧАЛОПЕРИОДА(ПартииТоваровНаСкладахОстаткиИОбороты.Период, МЕСЯЦ) КАК Период,
ПартииТоваровНаСкладахОстаткиИОбороты.Номенклатура КАК Номенклатура,
ПартииТоваровНаСкладахОстаткиИОбороты.Склад КАК Склад,
СУММА(ПартииТоваровНаСкладахОстаткиИОбороты.КоличествоНачальныйОстаток) КАК НачальныйОстаток,
СУММА(ПартииТоваровНаСкладахОстаткиИОбороты.КоличествоКонечныйОстаток) КАК КонечныйОстаток,
РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(&НачалоПериода, МЕСЯЦ), КОНЕЦПЕРИОДА(&КонецПериода, МЕСЯЦ), ДЕНЬ) + 1 КАК ДнейВПериоде
ИЗ
РегистрНакопления.ПартииТоваровНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Месяц, , {(Склад).* КАК Склад, (Номенклатура).* КАК Номенклатура}) КАК ПартииТоваровНаСкладахОстаткиИОбороты
СГРУППИРОВАТЬ ПО
НАЧАЛОПЕРИОДА(ПартииТоваровНаСкладахОстаткиИОбороты.Период, МЕСЯЦ),
ПартииТоваровНаСкладахОстаткиИОбороты.Номенклатура,
ПартииТоваровНаСкладахОстаткиИОбороты.Склад
В данном примере поле ДнейВПериоде является константой для всего отчета. Выясним причину, по которой его исключение из вывода ломает логику виртуальной таблицы.
Начиная с релизов ветки 8.3.27, разработчики платформы внедрили более агрессивную оптимизацию SQL-запросов, генерируемых СКД. Теперь система пытается максимально сократить текст запроса к СУБД, выбрасывая те поля и группировки, которые не участвуют в финальном отображении данных.
Если в схеме компоновки данных для полей измерений (Склад, Номенклатура) или периода не указаны жесткие правила их поведения, СКД может решить, что их можно не учитывать при расчете промежуточных итогов. В результате вместо получения срезов на начало и конец периода, платформа выполняет простое сложение всех записей, попадающих в выборку. Именно наличие расчетного поля (такого как РАЗНОСТЬДАТ) часто "заставляло" оптимизатор выполнять запрос более полно, что скрывало проблему в старых версиях платформы.
Самый правильный путь решения проблемы — явное указание ролей для всех полей, участвующих в расчете остатков. Рассмотрим по шагам, как это сделать в конструкторе СКД:
Склад и Номенклатура.Период. В роли поля периода должен быть указан тип периода (например, "День", "Месяц") и также установлен флаг "Обязательное".После установки флага Обязательное, структура группировок в SQL-запросе сохранится неизменной, что позволит виртуальной таблице ОстаткиИОбороты корректно вычислить значения ресурсов.
Опыт эксплуатации виртуальных таблиц в СКД показывает, что расчет остатков (особенно при использовании периодичности) работает стабильнее, если в выборку включены поля оборотов. Рассмотрим обновленный вариант запроса:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
ПартииТоваровНаСкладахОстаткиИОбороты.Период КАК Период,
ПартииТоваровНаСкладахОстаткиИОбороты.Номенклатура КАК Номенклатура,
ПартииТоваровНаСкладахОстаткиИОбороты.Склад КАК Склад,
ПартииТоваровНаСкладахОстаткиИОбороты.КоличествоНачальныйОстаток КАК НачальныйОстаток,
ПартииТоваровНаСкладахОстаткиИОбороты.КоличествоПриход КАК Приход,
ПартииТоваровНаСкладахОстаткиИОбороты.КоличествоРасход КАК Расход,
ПартииТоваровНаСкладахОстаткиИОбороты.КоличествоКонечныйОстаток КАК КонечныйОстаток
ИЗ
РегистрНакопления.ПартииТоваровНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Месяц, , ) КАК ПартииТоваровНаСкладахОстаткиИОбороты
Добавление полей КоличествоПриход и КоличествоРасход (даже если они не будут выведены в отчет) дает СКД дополнительный контекст. Платформа понимает, что перед ней полноценная таблица движений, и реже допускает ошибки при сворачивании итогов.
Заметим, что в исходном запросе автора присутствовала конструкция СГРУППИРОВАТЬ ПО. В СКД использование ручной группировки в основном тексте запроса при работе с виртуальными таблицами остатков часто является избыточным или даже вредным.
Рассмотрим рекомендации:
СГРУППИРОВАТЬ ПО внутри запроса СКД, если вы просто выбираете данные из таблицы ОстаткиИОбороты.При использовании платформы 8.3.27 рекомендуется выполнить "перезагрузку" метаданных схемы:
Выясним также важный момент: если вы используете расчетные выражения для периодов (как НАЧАЛОПЕРИОДА(Период, МЕСЯЦ)), убедитесь, что в параметрах виртуальной таблицы указана соответствующая периодичность (в нашем случае Месяц). Несоответствие периодичности виртуальной таблицы и группировок в запросе — частая причина "бредовых" остатков.
Подводя итог, можно сказать, что переход на новые релизы платформы требует более ответственного подхода к описанию метаданных внутри СКД. Использование флага "Обязательное" в ролях полей становится не просто рекомендацией, а необходимым условием для получения достоверной отчетности в 1С.