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