Как в запросе 1С ограничить выборку партий по количеству (метод FIFO)?

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

В процессе разработки систем автоматизации на платформе 1С:Предприятие часто возникает необходимость списания партий товаров по методу FIFO (первым пришел — первым ушел). Задача усложняется, когда требуется выбрать не фиксированное количество записей, а ровно столько партий, сколько необходимо для покрытия заданного количества товара (например, 8 единиц). Давайте разберем, как решить эту задачу в рамках языка запросов и когда стоит предпочесть другие методы.

Реализация FIFO через механизм нарастающего итога в запросе

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

Для реализации этого подхода выполним следующие шаги:

  1. Сначала выберем остатки партий во временную таблицу, чтобы работать с актуальными данными.
  2. Выполним соединение временной таблицы с её копией, чтобы рассчитать нарастающий итог.
  3. Используем секцию ИМЕЮЩИЕ для отсечения партий, которые превышают нужный лимит (в нашем примере — 8 единиц).

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


ВЫБРАТЬ
    ПартииТоваровКомпанииОстатки.Партия.МоментВремени КАК ПартияМоментВремени,
    ПартииТоваровКомпанииОстатки.КоличествоОстаток КАК КоличествоОстаток,
    ПартииТоваровКомпанииОстатки.СуммаОстаток КАК СуммаОстаток
ПОМЕСТИТЬ втПартии
ИЗ
    РегистрНакопления.ПартииТоваровКомпании.Остатки(&МоментСреза, Номенклатура = &Номенклатура И СкладКомпании = &СкладКомпании) КАК ПартииТоваровКомпанииОстатки
;

ВЫБРАТЬ
    втПартии.ПартияМоментВремени КАК ПартияМоментВремени,
    втПартии.КоличествоОстаток КАК КоличествоОстаток,
    втПартии.СуммаОстаток КАК СуммаОстаток,
    СУММА(втПартииНарастающее.КоличествоОстаток) КАК КоличествоНарастающийИтог
ИЗ
    втПартии КАК втПартии
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ втПартии КАК втПартииНарастающее
    ПО (втПартии.ПартияМоментВремени >= втПартииНарастающее.ПартияМоментВремени)

СГРУППИРОВАТЬ ПО
    втПартии.ПартияМоментВремени,
    втПартии.КоличествоОстаток,
    втПартии.СуммаОстаток

ИМЕЮЩИЕ
    СУММА(втПартииНарастающее.КоличествоОстаток) - втПартии.КоличествоОстаток <= 8

Анализ производительности и альтернативный подход

Рассмотренный выше запрос является классическим решением, однако мы должны помнить о производительности. Операция самосоединения («каждый с каждым») имеет квадратичную сложность. Если в регистре накопились тысячи партий, такой запрос может работать крайне медленно и блокировать таблицы базы данных.

Рассмотрим более предпочтительный вариант — пост-обработку в коде 1С. Этот метод гораздо проще в отладке и часто работает быстрее:

  1. Выгружаем список партий из запроса без всяких сложных соединений, просто упорядочив их по МоментуВремени.
  2. Обходим результат запроса в цикле.
  3. Внутри цикла накапливаем сумму количества в переменной Счетчик.
  4. Как только Счетчик превысит нужное нам значение (8 единиц), мы прерываем цикл оператором Прервать.

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

Рекомендации по оптимизации

При выборе метода всегда задавайтесь вопросом об объемах данных:

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

← На главную