При работе с платформой 1С:Предприятие 8.3, особенно в контексте управляемых форм и динамических списков, часто возникает необходимость отображения актуальных данных, хранящихся в регистрах сведений. Виртуальная таблица СрезПоследних является мощным инструментом для решения этой задачи. Однако у разработчиков, как и у автора темы на форуме, могут возникнуть вопросы относительно корректного применения отборов, в частности, по реквизитам регистра сведений, когда источник данных динамического списка — это именно СрезПоследних. Давайте подробно разберем эту ситуацию и выясним, как избежать распространенных ошибок.
Прежде чем перейти к отборам, давайте вспомним, как работает виртуальная таблица СрезПоследних. Эта таблица предназначена для получения самой актуальной записи регистра сведений на заданный момент времени. Она возвращает для каждой уникальной комбинации значений измерений регистра только одну, самую позднюю по полю Период запись, которая была действительна на указанную дату среза. В результате работы этой виртуальной таблицы мы получаем не только измерения, но и все ресурсы и реквизиты регистра сведений.
Важно понимать разницу между измерениями, ресурсами и реквизитами:
Когда мы обращаемся к СрезПоследних, мы ожидаем увидеть все эти поля – измерения, ресурсы и реквизиты – в результате. Однако возникает вопрос: как правильно отбирать данные по реквизитам?
На форуме часто встречается мнение, что отбор имеет смысл только по измерениям, а по реквизитам или по регистратору отбирать нельзя. Это частично неверно и приводит к путанице. Действительно, ключевая особенность СрезаПоследних — это формирование среза по измерениям. Но это не означает, что реквизиты недоступны для отбора или что их нельзя использовать в условиях.
Основная проблема возникает, когда условие отбора по реквизиту помещается в секцию ГДЕ основного запроса после получения среза. Давайте рассмотрим этот сценарий:
В чем опасность такого подхода? Представим ситуацию: у нас есть регистр цен, и для одной номенклатуры (измерение) последняя цена (срез) имеет реквизит «Валюта» = «USD». Но нам нужны только цены, где «Валюта» = «RUB». Если мы сначала получим срез, а потом отфильтруем по Валюта = 'RUB', то запись с ценой в USD будет отброшена, но мы не получим предыдущую актуальную запись с ценой в RUB, если такая была. Мы просто потеряем нужную информацию, и фактически полученный срез не будет «последним» для нужного условия по реквизиту.
Сообщение 11 с форума точно подмечает: «У вас просто будет получаться неправильный СрезПоследних», если применять отбор таким образом. Мы получаем не тот срез, который нам нужен, а срез, из которого что-то просто отфильтровали.
Ключ к правильному решению заключается в том, чтобы передать условия отбора (как по измерениям, так и по реквизитам) непосредственно в параметры виртуальной таблицы СрезПоследних(). Это гарантирует, что сам срез будет формироваться уже с учетом этих условий, и результат будет корректным.
Сообщение 12 очень точно формулирует этот принцип:
«можно сделать срез последних с отбором по измерениям в параметре виртуальной таблицы. Потом в условии ГДЕ еще более конкретизировать выборку по реквизитам.»
Или еще более корректно: можно сделать срез последних с отбором по реквизитам в параметре виртуальной таблицы.
Рассмотрим подробнее шаги и примеры:
Виртуальная таблица СрезПоследних() позволяет передавать два параметра:
ДатаСреза: Момент времени, на который мы хотим получить последние записи.УсловияОтбора: Строка с условиями отбора, которые будут применены к данным регистра до формирования среза. Это могут быть условия по измерениям, ресурсам или реквизитам.Например, если у нас есть регистр сведений «ЦеныНоменклатуры», который содержит измерения «Номенклатура», «ТипЦен» и реквизит «НаценкаПроцент», и мы хотим получить последние цены только для определенной номенклатуры и только те, у которых наценка меньше или равна 50%, запрос будет выглядеть так:
Мы используем язык запросов 1С.
ВЫБРАТЬ
СрезПоследних.Номенклатура,
СрезПоследних.ТипЦен,
СрезПоследних.Цена,
СрезПоследних.НаценкаПроцент
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
&ДатаСреза,
"Номенклатура = &ВыбраннаяНоменклатура И НаценкаПроцент <= &МаксимальнаяНаценка"
) КАК СрезПоследних
В этом примере:
&ДатаСреза – это параметр, который передает момент среза.&ВыбраннаяНоменклатура – это параметр для измерения «Номенклатура».&МаксимальнаяНаценка – это параметр для реквизита «НаценкаПроцент».Платформа сначала найдет все записи по Номенклатура = &ВыбраннаяНоменклатура И НаценкаПроцент <= &МаксимальнаяНаценка до &ДатаСреза, а затем уже из этого отфильтрованного набора сформирует срез последних. Таким образом, мы получаем именно тот «срез последних», который соответствует нашим критериям по реквизиту.
Для более сложного отбора или когда отбор формируется динамически, можно использовать структуру для передачи параметров отбора. Это особенно удобно в программном коде при построении запроса:
// Пример программного создания запроса
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СрезПоследних.Номенклатура,
| СрезПоследних.ТипЦен,
| СрезПоследних.Цена,
| СрезПоследних.НаценкаПроцент
|ИЗ
| РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
| &ДатаСреза,
| &ПараметрыОтбора
| ) КАК СрезПоследних";
// Параметры для СрезаПоследних
ДатаСреза = ТекущаяДата();
Запрос.УстановитьПараметр("ДатаСреза", ДатаСреза);
// Параметры отбора, передаваемые в СрезПоследних
СтруктураПараметровОтбора = Новый Структура;
СтруктураПараметровОтбора.Вставить("Номенклатура", СсылкаНаНоменклатуру);
СтруктураПараметровОтбора.Вставить("НаценкаПроцент", 50); // Отбор по реквизиту
Запрос.УстановитьПараметр("ПараметрыОтбора", СтруктураПараметровОтбора);
Результат = Запрос.Выполнить().Выбрать();
При использовании структуры в качестве второго параметра метода СрезПоследних(), ключи структуры должны соответствовать именам полей регистра (измерений, ресурсов или реквизитов), по которым производится отбор. Значения структуры будут использоваться как значения отбора.
После того как вы сформировали корректный срез последних с учетом всех необходимых условий в параметрах виртуальной таблицы, вы можете добавить дополнительные условия в секцию ГДЕ основного запроса. Это может быть полезно для фильтрации результатов по каким-либо ресурсам или реквизитам, которые не являются критически важными для формирования самого среза, но нужны для дальнейшей обработки. В этом случае, если запись не соответствует условию в ГДЕ, она просто будет отброшена из уже сформированного и корректного набора «последних» данных.
ВЫБРАТЬ
СрезПоследних.Номенклатура,
СрезПоследних.ТипЦен,
СрезПоследних.Цена,
СрезПоследних.НаценкаПроцент
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
&ДатаСреза,
"Номенклатура = &ВыбраннаяНоменклатура"
) КАК СрезПоследних
ГДЕ
СрезПоследних.Цена > &МинимальнаяЦена
И СрезПоследних.НаценкаПроцент <= &МаксимальнаяНаценка
В этом примере мы формируем срез последних для выбранной номенклатуры, а уже потом из полученного набора отбираем только те записи, где цена больше минимальной и наценка меньше или равна максимальной. Здесь НаценкаПроцент используется в ГДЕ, но сам срез уже был сформирован для корректных измерений. Если бы НаценкаПроцент была критична для *формирования* среза, ее следовало бы включить во второй параметр СрезПоследних().
В контексте динамического списка, где источником данных является запрос к СрезПоследних, рекомендуется передавать параметры отбора непосредственно в запрос, формирующий этот срез. Это можно сделать несколькими способами:
&ПараметрНоменклатура) и затем в коде или в свойствах динамического списка (на закладке "Параметры") связать их с элементами формы или значениями.СрезПоследних().При использовании динамического списка, свойства "Отбор" самого списка также могут применяться. Однако, если вы добавляете отбор по реквизиту через стандартный механизм отбора динамического списка, это эквивалентно добавлению условия в секцию ГДЕ основного запроса динамического списка. В этом случае действует то же правило: сначала формируется срез, а затем из него отфильтровываются записи. Чтобы избежать ошибок, наиболее критичные условия по реквизитам, влияющие на определение "последней" записи, следует включать в параметры виртуальной таблицы СрезПоследних().
Мы также должны рассмотреть ситуации, когда использование СрезПоследних может привести к нежелательным результатам:
Период), то метод СрезПоследних() для него неприменим, и будет выброшено исключение.СрезПоследних() вы не передадите обязательные измерения (если регистр подчинен регистратору, например, и в измерениях регистра есть ссылка на этот регистратор), это может привести к некорректным данным или ошибке. Однако это не относится к виртуальной таблице в запросе, которая автоматически определяет измерения регистра.Мы выяснили, что отбор по реквизитам в виртуальной таблице СрезПоследних не только возможен, но и необходим для получения корректных данных в ряде случаев. Критически важно применять условия отбора по реквизитам (и другим полям) непосредственно в параметрах виртуальной таблицы СрезПоследних(), чтобы сам срез формировался уже с учетом этих условий. Дополнительные условия в секции ГДЕ можно использовать для дальнейшей фильтрации уже полученного корректного среза, если эти условия не влияют на логику определения "последней" записи.
Следуя этим рекомендациям, мы сможем эффективно использовать СрезПоследних для отображения точных и актуальных данных в наших управляемых формах и динамических списках 1С:Предприятия.