Как получить остатки по регистру бухгалтерии на список произвольных дат?

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

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

В этой статье мы рассмотрим несколько эффективных способов решения данной задачи, проанализируем их производительность и разберем технические нюансы реализации.

Решение 1: Использование Системы компоновки данных (СКД)

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

Разберем по шагам, как настроить получение остатков на каждый день или по списку дат:

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

Преимущество этого метода заключается в том, что платформа берет на себя сложный расчет итогов "на лету", обеспечивая при этом приемлемую скорость работы в большинстве типовых конфигураций, таких как 1С:Бухгалтерия 2.0.

Решение 2: Накопленный итог через таблицу оборотов (Запрос)

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

Проанализируем алгоритм реализации:

  1. Подготовим временную таблицу ВТ_Даты, в которую поместим наш список произвольных дат. Обязательно проиндексируем поле Дата.
  2. Получим начальный остаток на самую раннюю дату из нашего списка.
  3. Выберем все обороты по счету за период с минимальной до максимальной даты из списка.
  4. Соединим таблицу ВТ_Даты с таблицей оборотов по условию Обороты.Период <= ВТ_Даты.Дата.
  5. Сгруппируем результат по дате из списка и вычислим остаток как сумму начального остатка и всех оборотов, предшествующих этой дате.

Пример структуры такого запроса:


ВЫБРАТЬ
    Т_Даты.Дата КАК Период,
    ЕСТЬNULL(НачОстатки.СуммаОстатокДт, 0) + СУММА(ЕСТЬNULL(Обороты.СуммаОборотДт, 0) - ЕСТЬNULL(Обороты.СуммаОборотКт, 0)) КАК ОстатокНаДату
ИЗ
    ВТ_Даты КАК Т_Даты
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.Остатки(&НачалоПериода, Счет = &НужныйСчет) КАК НачОстатки ПО ИСТИНА
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.Обороты(&НачалоПериода, &КонецПериода, День, Счет = &НужныйСчет) КАК Обороты
    ПО Обороты.Период <= Т_Даты.Дата
ГРУППИРОВАТЬ ПО
    Т_Даты.Дата,
    НачОстатки.СуммаОстатокДт

Решение 3: Соединение с виртуальной таблицей в цикле (для малых списков)

Если дат в списке немного (например, 3-5), иногда проще и быстрее выполнить запрос в цикле или использовать пакетный запрос с несколькими обращениями к виртуальной таблице Остатки. Рассмотрим ситуацию, когда мы передаем конкретную дату в параметр таблицы.

Важно помнить: 1С не позволяет передать значение поля одной таблицы в параметр виртуальной таблицы другой таблицы в рамках одного запроса. Поэтому код вида ЛЕВОЕ СОЕДИНЕНИЕ Регистр.Остатки(Т_Даты.Дата) не сработает. Нам придется либо использовать временные таблицы для каждой даты, либо выполнять расчет через соединение с таблицей движений, фильтруя их по условию ГДЕ.

Проблемы производительности и важные рекомендации

Выясним, почему некоторые запросы работают медленно и как это исправить:

  1. Расчет итогов "на лету": Виртуальная таблица Остатки рассчитывает данные от ближайшей точки хранения итогов (обычно начало месяца). Если вы запрашиваете остатки на 31 число каждого дня месяца через тяжелое соединение, система может выполнить 31 полноценный расчет. Для оптимизации всегда старайтесь ограничивать выборку конкретными счетами и субконто внутри параметров виртуальной таблицы.
  2. Индексация: При использовании временных таблиц со списком дат обязательно индексируйте поле даты. Без этого соединение с таблицей движений регистра (которая может содержать миллионы записей) приведет к катастрофическому замедлению из-за сканирования всей таблицы (Full Scan).
  3. Обработка NULL: При левом соединении таблицы дат с таблицей остатков или оборотов всегда используйте функцию ЕСТЬNULL. Если на определенную дату движений не было, запрос вернет NULL, что при сложении с числами даст пустой результат.
  4. Границы периодов: Обратите внимание, что для получения остатка на "конец дня" в качестве параметра даты нужно передавать либо КОНЕЦПЕРИОДА(НужнаяДата, ДЕНЬ), либо использовать объект Граница с включением моментов времени последних документов дня.

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

← На главную