Как получить остатки на каждый день в СКД

Программист 1С v8.3 (Управляемые формы) Управленческий учет
← На главную

Одной из классических задач при разработке отчетов в системе компоновки данных (СКД) является получение остатков на каждую дату заданного периода. Сложность заключается в том, что в регистрах накопления 1С данные хранятся только на моменты движений. Если в какой-то день операций не было, виртуальная таблица остатков просто не вернет строку для этой даты. Разберем подробно несколько эффективных способов решения этой задачи, от простых настроек интерфейса до оптимизированных запросов.

Способ 1: Использование стандартного механизма дополнения периодов

Это самый «нативный» и зачастую самый простой способ, который реализуется средствами самой СКД. Рассмотрим его по шагам:

  1. Настройка роли поля: В наборе данных (запросе) для поля, отвечающего за дату (например, Период), необходимо правильно настроить колонку Роль. Откройте конструктор схемы компоновки данных, перейдите на закладку «Наборы данных» и в поле «Роль» для периода укажите, что это «Период» с типом (например, «День»).
  2. Настройка группировки: Перейдем на вкладку «Настройки». Добавим группировку по полю Период.
  3. Дополнение дат: В нижней части окна настроек выберем вкладку «Иерархия и группировки». Для выбранного поля периода установим свойство Тип дополнения в значение День. Также необходимо указать Начало периода и Конец периода (обычно это параметры отчета &НачалоПериода и &КонецПериода).

Проанализируем ситуацию: в этом случае СКД сама «дорисует» недостающие даты в отчет. Важно помнить, что если вы рассчитываете остатки, то в пустых строках (где не было движений) СКД автоматически продублирует значение остатка из предыдущего периода, если правильно настроены роли полей остатков.

Способ 2: Соединение двух наборов данных в СКД

Этот метод часто называют методом «календаря». Суть его в том, что мы создаем один набор данных, который содержит только список всех дат периода, и соединяем его со вторым набором, содержащим остатки.

Разберем алгоритм реализации:

  1. Создаем первый набор данных (НаборДаты): Это может быть запрос к производственному календарю или виртуальной таблице, которая гарантированно содержит все дни.
    
    ВЫБРАТЬ
        РегламентированныйПроизводственныйКалендарь.ДатаКалендаря КАК ДатаПериода
    ИЗ
        РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь
    ГДЕ
        РегламентированныйПроизводственныйКалендарь.ДатаКалендаря МЕЖДУ &НачалоПериода И &КонецПериода
    
  2. Создаем второй набор данных (НаборОстатки): Здесь мы используем виртуальную таблицу остатков регистра. В параметрах виртуальной таблицы (Период) указываем параметр, который будет передаваться из первого набора.
    
    ВЫБРАТЬ
        ВзаиморасчетыОстатки.СуммаОстаток КАК СуммаОстаток,
        &ДатаДляОстатков КАК Период
    ИЗ
        РегистрНакопления.Взаиморасчеты.Остатки(&ДатаДляОстатков, ) КАК ВзаиморасчетыОстатки
    
  3. Связи наборов данных: На вкладке «Связи наборов данных» связываем НаборДаты (источник) с НаборОстатки (приемник). В колонке «Параметр» для связи указываем имя параметра виртуальной таблицы остатков (в нашем примере ДатаДляОстатков), а в качестве выражения связи — ДатаПериода.

Важное замечание: Этот метод может быть медленным на больших периодах и больших объемах номенклатуры, так как система будет выполнять отдельный запрос к базе данных для каждой даты. Рассмотрим ситуацию: если отчет строится за год, 1С выполнит 365 микро-запросов, что существенно снизит производительность.

Способ 3: Формирование таблицы дат и остатков в одном запросе (UNION)

Если нам нужна максимальная скорость, лучше подготовить данные в одном запросе, используя временные таблицы. Идея заключается в том, чтобы получить начальный остаток на начало всего периода и объединить его с ежедневными оборотами.

Посмотрим на пример логики построения такого запроса:


// 1. Получаем все даты, в которые были движения
ВЫБРАТЬ РАЗЛИЧНЫЕ
    НАЧАЛОПЕРИОДА(Хозрасчетный.Период, ДЕНЬ) КАК Период
ПОМЕСТИТЬ ВТ_Даты
ИЗ
    РегистрНакопления.ТоварыНаСкладах КАК Хозрасчетный
ГДЕ
    Хозрасчетный.Период МЕЖДУ &НачалоПериода И &КонецПериода;

////////////////////////////////////////////////////////////////////////////////
// 2. Получаем начальный остаток и все обороты по дням
ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, -1) КАК Период,
    Остатки.КоличествоОстаток КАК Количество
ПОМЕСТИТЬ ВТ_Движения
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(&НачалоПериода, ) КАК Остатки

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    Обороты.Период,
    Обороты.КоличествоОборот
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Обороты(&НачалоПериода, &КонецПериода, День, ) КАК Обороты;

////////////////////////////////////////////////////////////////////////////////
// 3. Соединяем даты с движениями для расчета нарастающего итога
ВЫБРАТЬ
    Даты.Период КАК Период,
    СУММА(Движения.Количество) КАК ОстатокНаДень
ИЗ
    ВТ_Даты КАК Даты
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Движения КАК Движения
    ПО Движения.Период <= Даты.Период
СГРУППИРОВАТЬ ПО
    Даты.Период

Проанализируем этот код: мы используем левое соединение таблицы дат с таблицей всех движений по условию Движения.Период <= Даты.Период. Это позволяет для каждой даты просуммировать все изменения, произошедшие до этого момента включительно, что и является остатком на конец дня. Для реализации альтернативных вариантов формирования периодов и остатков в запросе можно использовать примеры построения выборки диапазона дат и среза остатков в запросе.

Способ 4: Использование функции СКД «ВычислитьВыражение»

Это наиболее современный и производительный подход для работы в СКД. Мы можем получить только обороты по дням и начальный остаток, а сам остаток на каждый день рассчитать уже на уровне ресурсов компоновки данных.

Для этого в ресурсах СКД для поля Остаток прописывается формула:

ВычислитьВыражение("Сумма(Оборот)", "Период", "Группировка", "Первая", "Текущая") + Сумма(НачальныйОстаток)

Выясним причину эффективности этого метода: расчет происходит в памяти сервера приложений 1С после получения плоской таблицы данных из БД. Это избавляет базу данных от тяжелых соединений «многие-ко-многим», которые возникают при расчете нарастающего итога в запросе (как в Способе 3). При необходимости можно изучить примеры отчетов СКД с использованием сложных выражений в ресурсах.

Важные нюансы и рекомендации

При работе с остатками по дням следует учитывать следующие моменты:

Рассмотрев все варианты, мы видим, что выбор метода зависит от конкретной задачи: для простых отчетов достаточно штатного «дополнения дат» в настройках СКД, а для сложных и высоконагруженных систем лучше использовать расчет нарастающего итога через ресурсы компоновки.

← На главную