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