Как получить цену товара на каждую конкретную дату продажи в 1С с помощью запроса?

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

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

Понимание сути проблемы

Когда мы работаем с продажами, каждая транзакция совершается в определенный момент времени. В регистре Цены значения могут меняться редко. Нам нужно для каждой даты продажи найти такое значение Период в регистре цен, которое было бы максимально приближенным к дате продажи, но не превышало её (ПериодЦена <= ПериодПродажи). Простого соединения таблиц здесь недостаточно, так как мы получим декартово произведение всех прошлых цен.

Решение методом поиска максимального периода

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

  1. Сначала мы формируем список уникальных дат и товаров из регистра продаж.
  2. Далее мы соединяем этот список с регистром Цены по условию, где дата установки цены меньше или равна дате продажи.
  3. Группируем полученные данные по дате продажи и товару, вычисляя МАКСИМУМ(Период) из регистра цен. Это и есть та самая «последняя» цена на нужный момент.
  4. На финальном этапе соединяем результат с таблицей цен, чтобы получить конкретное значение ресурса Цена.

Пример реализации запроса

Посмотрим, как выглядит подобный запрос на практике. Обратите внимание на использование ПОМЕСТИТЬ для создания временных таблиц, что значительно упрощает читаемость и повышает производительность.


ВЫБРАТЬ 
    Продажи.Товар КАК Товар,
    Продажи.Период КАК ДатаПродажи,
    МАКСИМУМ(Цены.Период) КАК ПериодЦены
ПОМЕСТИТЬ ВТ_ПериодыДляЦен
ИЗ 
    РегистрСведений.Продажи КАК Продажи
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Цены КАК Цены
    ПО Продажи.Товар = Цены.Товар 
    И Продажи.Период >= Цены.Период
СГРУППИРОВАТЬ ПО 
    Продажи.Товар, 
    Продажи.Период
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ 
    ВТ.ДатаПродажи,
    ВТ.Товар,
    Цены.Цена
ИЗ 
    ВТ_ПериодыДляЦен КАК ВТ
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.Цены КАК Цены
    ПО ВТ.Товар = Цены.Товар 
    И ВТ.ПериодЦены = Цены.Период

Почему это лучше других способов?

Многие новички пытаются выполнить РегистрыСведений.Цены.СрезПоследних() внутри цикла обхода результата запроса. Это считается «антипаттерном» в среде разработчиков 1С. Почему? Потому что каждый вызов СрезПоследних в цикле — это отдельный запрос к базе данных. Если у вас 10 000 строк продаж, система выполнит 10 000 запросов, что приведет к катастрофическому замедлению работы отчета или обработки.

Предложенный выше пакетный запрос выполняется на сервере БД одним махом. Оптимизатор СУБД обрабатывает временную таблицу как полноценный набор данных, что работает в десятки, а иногда и в сотни раз быстрее.

Важные рекомендации по доработке

Теперь вы знаете, как профессионально решить задачу получения исторических данных о ценах. Используйте временные таблицы, группировки по максимуму и избегайте запросов в циклах — это сделает ваш код чище и быстрее!

← На главную