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