Как получить остатки на произвольный список дат в запросе 1С

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

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

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

Метод 1: Соединение с физической таблицей движений

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

Предположим, у нас уже есть временная таблица ВТ_Даты с колонками Дата, Клиент, Фирма. Нам нужно получить остатки по этим измерениям на каждую указанную дату. Проанализируем структуру запроса:

1. Мы выполняем ЛЕВОЕ СОЕДИНЕНИЕ временной таблицы с физической таблицей регистра накопления.
2. Условие связи устанавливается по измерениям (Клиент, Фирма) и по периоду: Регистр.Период <= ВТ_Даты.Дата.

Разберем пример реализации расчета суммы остатка. Так как в физической таблице нет готового поля «Остаток», мы должны использовать конструкцию ВЫБОР, чтобы правильно учесть приходы и расходы:


ВЫБРАТЬ
    Т.Дата КАК Дата,
    Т.Клиент КАК Клиент,
    Т.Фирма КАК Фирма,
    СУММА(ВЫБОР
            КОГДА Рег.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
                ТОГДА Рег.Сумма
            ИНАЧЕ -Рег.Сумма
        КОНЕЦ) КАК ОстатокНаДату
ИЗ
    ВТ_Даты КАК Т
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Взаиморасчеты КАК Рег
        ПО Т.Клиент = Рег.Клиент
            И Т.Фирма = Рег.Фирма
            И Рег.Период <= Т.Дата
СГРУППИРОВАТЬ ПО
    Т.Дата,
    Т.Клиент,
    Т.Фирма

Важный нюанс: при использовании условия <= в запросе по физической таблице мы фактически получаем остаток «на конец секунды». Если в эту же секунду были движения, они попадут в расчет. Если вам нужен остаток «на начало», используйте строгое сравнение <.

Метод 2: Оптимизация через «Начальный остаток + Обороты»

Метод прямого суммирования физической таблицы (Метод 1) прост в реализации, но имеет существенный недостаток: для каждой даты из вашего списка система вынуждена заново пересчитывать все движения «с начала времен». Если в регистре миллионы записей, запрос будет работать крайне медленно.

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

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

Такой подход значительно снижает нагрузку на базу данных, так как мы не сканируем исторические данные многократно для каждой строки списка.

Метод 3: Работа с пустующими датами

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

Проанализируем ситуацию: если движений не было, сумма по полю Остаток может вернуться как NULL. Не забудьте обработать это значение функцией ЕСТЬNULL(..., 0), чтобы в отчете красовался ноль, а не пустое поле.

Технические тонкости: Индексация и Границы

Для обеспечения максимальной скорости работы запроса необходимо соблюдать правила индексации. Рассмотрим основные моменты:

Индексация временных таблиц: Всегда индексируйте временную таблицу ВТ_Даты по тем полям, по которым происходит соединение. В нашем примере это Дата, Клиент и Фирма.


ИНДЕКСИРОВАТЬ ПО
    Дата,
    Клиент,
    Фирма

Понятие Границы (Boundary): В 1С существует объект Граница, который определяет, включать ли момент времени в расчет. В запросах это моделируется условиями сравнения. Если ваша задача — получить остаток на КОНЕЦПЕРИОДА(Дата, ДЕНЬ), убедитесь, что условие в запросе корректно обрабатывает время 23:59:59. Использование <= КОНЕЦПЕРИОДА(Дата, ДЕНЬ) является наиболее безопасным вариантом для получения остатка на конец дня.

Резюме

Мы рассмотрели несколько способов получения остатков на произвольные даты. Выбор метода зависит от объема данных:

Помните, что грамотное использование временных таблиц и индексации — залог стабильной работы вашей системы 1С.

← На главную