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