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