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