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