Как определить дату, когда цена впервые была установлена равной текущей?

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

В процессе автоматизации печати ценников в Управление торговлей 10.3 часто возникает задача: нужно не просто получить текущую цену товара, а найти дату, с которой эта цена действует непрерывно. Ситуация осложняется тем, что в регистре сведений ЦеныНоменклатуры могут существовать записи с одинаковыми значениями цены, сделанные в разные дни. Если мы просто возьмем дату последней записи, мы можем получить дату, когда цена была «переустановлена» (обновлена тем же значением), а нам нужно найти момент самого первого изменения, которое привело к текущему уровню цен.

Разбор проблемы

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

Решение через язык запросов 1С

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

Шаг 1: Формируем текущее состояние цен

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


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

Шаг 2: Поиск предыдущего изменения цены

Теперь самое интересное. Нам нужно найти дату самого последнего изменения цены, когда она не была равна текущей. Мы делаем ЛЕВОЕ СОЕДИНЕНИЕ регистра с самим собой, отфильтровывая записи, где цена изменилась, и находим максимальную дату среди таких событий.


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

В этом запросе мы используем важное условие: ВТ_ВсеЦены.Цена <> ЦеныНоменклатуры.Цена. Это позволяет отсечь все «дублирующие» записи, где цена оставалась неизменной, и найти именно ту точку во времени, где произошло последнее отклонение от текущего значения.

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

  1. Минимизация записи в регистр: Самый эффективный способ решения этой проблемы — не допускать появления «дублей» в регистре. Рекомендуется в событии ПередЗаписью регистра ЦеныНоменклатуры проверять, изменилась ли цена по сравнению с последней записью. Если цена не изменилась, запись можно отклонить. Это сэкономит место в базе и избавит от необходимости писать сложные запросы.
  2. Индексация: Убедитесь, что на поля Номенклатура, ТипЦен и Период установлены индексы в конфигураторе, так как именно по ним происходит основное соединение в запросе.
  3. Массовая обработка: Если вы печатаете ценники для большого списка товаров, всегда собирайте данные одним запросом для всей ТаблицаТоваров, а не выполняйте Запрос.Выполнить() в цикле для каждой строки — это критически замедлит работу системы.

Используя данный подход, вы сможете корректно выводить дату установки цены на ценниках, даже если в системе накопилось множество избыточных записей об установке цен с одинаковыми значениями.

← На главную