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