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