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