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