Как в запросе 1С получить только измененные цены за определенный период

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

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

Разберем подробно, как построить эффективный запрос для решения этой задачи, проанализируем различные подходы и выясним причины, по которым стоит выбирать тот или иной метод.

Метод 1. Сопоставление документов и текущих срезов

Рассмотрим первый подход, который часто приходит на ум начинающим разработчикам. Он заключается в анализе документов УстановкаЦенНоменклатуры, созданных за выбранный период, и их сравнении с данными регистра на начало этого периода.

Проанализируем этот алгоритм по шагам:

  1. Создадим первый пакет запроса, в котором выберем данные из документа УстановкаЦенНоменклатуры (или его табличной части). Установим фильтр по дате: Дата МЕЖДУ &НачалоПериода И &КонецПериода.
  2. Во втором пакете обратимся к виртуальной таблице СрезПоследних регистра сведений ЦеныНоменклатуры на дату &НачалоПериода.
  3. Выполним левое соединение первого пакета со вторым по полям Номенклатура (и Характеристика, если она используется).
  4. В условии фильтрации (блок ГДЕ) укажем, что нас интересуют записи, где Цена из документа не равна Цене из среза последних, либо где запись в срезе последних отсутствует (ЕСТЬNULL), что будет означать появление новой цены для товара.

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

Метод 2. Работа с физической таблицей регистра сведений

Рассмотрим более универсальный и надежный способ — использование физической таблицы регистра сведений ЦеныНоменклатуры. Это позволит нам увидеть все изменения, независимо от того, каким регистратором они были внесены.

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


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

СГРУППИРОВАТЬ ПО
    ЦеныЗаПериод.Номенклатура,
    ЦеныЗаПериод.Характеристика
;

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

В данном примере мы сначала собираем все факты изменения цен за неделю во временную таблицу ВТ_ПоследниеИзменения. Важно сгруппировать данные, чтобы получить именно последнюю установленную цену внутри периода, если за неделю цена на один и тот же товар менялась несколько раз.

Анализ проблемы «фиктивных» изменений

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

Для решения этой проблемы мы используем Левое соединение со СрезомПоследних на начало периода. Условие РеалЦены.Цена <> ЦеныНаНачало.Цена отсекает такие «пустые» записи. При этом использование ЕСТЬNULL(ЦеныНаНачало.Цена, 0) позволяет нам корректно обработать ситуацию с новыми товарами: если старой цены не существует, ЕСТЬNULL вернет 0, и условие неравенства сработает, включив товар в отчет.

Учет характеристик и единиц измерения

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

Оптимизация производительности

Если ваша база данных содержит сотни тысяч наименований товаров, запрос может работать медленно. Разберем, как его ускорить:

Во-первых, всегда передавайте параметры в виртуальные таблицы. Вместо того чтобы писать ГДЕ ВидЦены = &ВидЦены после соединения со СрезомПоследних, укажите это условие непосредственно в параметрах виртуальной таблицы: ЦеныНоменклатуры.СрезПоследних(&Дата, ВидЦены = &ВидЦены). Это позволит системе отфильтровать данные на уровне сервера СУБД, не выгружая лишние записи в оперативную память.

Во-вторых, используйте Временные таблицы. Как показано в примере выше, разделение сложного запроса на несколько простых этапов с помещением промежуточных результатов во временные таблицы (с индексацией по номенклатуре) значительно повышает общую производительность, так как планировщик задач SQL лучше оптимизирует такие запросы.

Особенности динамических цен

Выясним важный нюанс: в 1С существуют «Динамические» виды цен. Эти цены не хранятся физически в регистре ЦеныНоменклатуры, а рассчитываются «на лету» на основании базовой цены и какой-либо наценки. Если вы попытаетесь найти изменения динамической цены через физическую таблицу регистра, вы ничего не найдете.

Для работы с динамическими ценами логика должна быть другой: нужно отслеживать изменения базовой цены, от которой они зависят. Если базовая цена изменилась — значит, формально изменилась и динамическая.

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

← На главную