Как правильно сделать отбор по реквизиту в виртуальной таблице «СрезПоследних» регистра сведений для динамического списка?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с платформой 1С:Предприятие 8.3, особенно в контексте управляемых форм и динамических списков, часто возникает необходимость отображения актуальных данных, хранящихся в регистрах сведений. Виртуальная таблица СрезПоследних является мощным инструментом для решения этой задачи. Однако у разработчиков, как и у автора темы на форуме, могут возникнуть вопросы относительно корректного применения отборов, в частности, по реквизитам регистра сведений, когда источник данных динамического списка — это именно СрезПоследних. Давайте подробно разберем эту ситуацию и выясним, как избежать распространенных ошибок.

Особенности работы виртуальной таблицы "СрезПоследних"

Прежде чем перейти к отборам, давайте вспомним, как работает виртуальная таблица СрезПоследних. Эта таблица предназначена для получения самой актуальной записи регистра сведений на заданный момент времени. Она возвращает для каждой уникальной комбинации значений измерений регистра только одну, самую позднюю по полю Период запись, которая была действительна на указанную дату среза. В результате работы этой виртуальной таблицы мы получаем не только измерения, но и все ресурсы и реквизиты регистра сведений.

Важно понимать разницу между измерениями, ресурсами и реквизитами:

  1. Измерения определяют уникальность записи в регистре сведений. Например, в регистре «ЦеныНоменклатуры» измерениями могут быть «Номенклатура» и «ТипЦен». Комбинация этих значений вместе с полем «Период» однозначно идентифицирует запись. По сути, измерения задают «разрезы» хранения информации.
  2. Ресурсы хранят основные данные, ради которых регистр был создан. В том же примере с ценами, ресурс будет хранить саму «Цена».
  3. Реквизиты содержат дополнительную информацию о записи, которая не участвует в формировании ее уникального ключа и не является основным хранимым значением. Например, реквизит может хранить дату создания записи, ответственного пользователя, комментарий или любое другое вспомогательное значение.

Когда мы обращаемся к СрезПоследних, мы ожидаем увидеть все эти поля – измерения, ресурсы и реквизиты – в результате. Однако возникает вопрос: как правильно отбирать данные по реквизитам?

Распространенные заблуждения при отборе по реквизитам

На форуме часто встречается мнение, что отбор имеет смысл только по измерениям, а по реквизитам или по регистратору отбирать нельзя. Это частично неверно и приводит к путанице. Действительно, ключевая особенность СрезаПоследних — это формирование среза по измерениям. Но это не означает, что реквизиты недоступны для отбора или что их нельзя использовать в условиях.

Основная проблема возникает, когда условие отбора по реквизиту помещается в секцию ГДЕ основного запроса после получения среза. Давайте рассмотрим этот сценарий:

  1. Сначала платформа формирует срез последних записей по всем уникальным комбинациям измерений (без учета вашего условия по реквизиту).
  2. Затем к этому уже сформированному результату применяется условие по реквизиту.

В чем опасность такого подхода? Представим ситуацию: у нас есть регистр цен, и для одной номенклатуры (измерение) последняя цена (срез) имеет реквизит «Валюта» = «USD». Но нам нужны только цены, где «Валюта» = «RUB». Если мы сначала получим срез, а потом отфильтруем по Валюта = 'RUB', то запись с ценой в USD будет отброшена, но мы не получим предыдущую актуальную запись с ценой в RUB, если такая была. Мы просто потеряем нужную информацию, и фактически полученный срез не будет «последним» для нужного условия по реквизиту.

Сообщение 11 с форума точно подмечает: «У вас просто будет получаться неправильный СрезПоследних», если применять отбор таким образом. Мы получаем не тот срез, который нам нужен, а срез, из которого что-то просто отфильтровали.

Правильный подход к отбору по реквизитам в «СрезеПоследних»

Ключ к правильному решению заключается в том, чтобы передать условия отбора (как по измерениям, так и по реквизитам) непосредственно в параметры виртуальной таблицы СрезПоследних(). Это гарантирует, что сам срез будет формироваться уже с учетом этих условий, и результат будет корректным.

Сообщение 12 очень точно формулирует этот принцип:

«можно сделать срез последних с отбором по измерениям в параметре виртуальной таблицы. Потом в условии ГДЕ еще более конкретизировать выборку по реквизитам.»

Или еще более корректно: можно сделать срез последних с отбором по реквизитам в параметре виртуальной таблицы.

Рассмотрим подробнее шаги и примеры:

1. Отбор в параметрах виртуальной таблицы «СрезПоследних»

Виртуальная таблица СрезПоследних() позволяет передавать два параметра:

  1. ДатаСреза: Момент времени, на который мы хотим получить последние записи.
  2. УсловияОтбора: Строка с условиями отбора, которые будут применены к данным регистра до формирования среза. Это могут быть условия по измерениям, ресурсам или реквизитам.

Например, если у нас есть регистр сведений «ЦеныНоменклатуры», который содержит измерения «Номенклатура», «ТипЦен» и реквизит «НаценкаПроцент», и мы хотим получить последние цены только для определенной номенклатуры и только те, у которых наценка меньше или равна 50%, запрос будет выглядеть так:

Мы используем язык запросов 1С.


ВЫБРАТЬ
    СрезПоследних.Номенклатура,
    СрезПоследних.ТипЦен,
    СрезПоследних.Цена,
    СрезПоследних.НаценкаПроцент
ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
        &ДатаСреза,
        "Номенклатура = &ВыбраннаяНоменклатура И НаценкаПроцент <= &МаксимальнаяНаценка"
    ) КАК СрезПоследних

В этом примере:

Платформа сначала найдет все записи по Номенклатура = &ВыбраннаяНоменклатура И НаценкаПроцент <= &МаксимальнаяНаценка до &ДатаСреза, а затем уже из этого отфильтрованного набора сформирует срез последних. Таким образом, мы получаем именно тот «срез последних», который соответствует нашим критериям по реквизиту.

2. Отбор с использованием структуры параметров

Для более сложного отбора или когда отбор формируется динамически, можно использовать структуру для передачи параметров отбора. Это особенно удобно в программном коде при построении запроса:


// Пример программного создания запроса
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    СрезПоследних.Номенклатура,
    |    СрезПоследних.ТипЦен,
    |    СрезПоследних.Цена,
    |    СрезПоследних.НаценкаПроцент
    |ИЗ
    |    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
    |        &ДатаСреза,
    |        &ПараметрыОтбора
    |    ) КАК СрезПоследних";

// Параметры для СрезаПоследних
ДатаСреза = ТекущаяДата();
Запрос.УстановитьПараметр("ДатаСреза", ДатаСреза);

// Параметры отбора, передаваемые в СрезПоследних
СтруктураПараметровОтбора = Новый Структура;
СтруктураПараметровОтбора.Вставить("Номенклатура", СсылкаНаНоменклатуру);
СтруктураПараметровОтбора.Вставить("НаценкаПроцент", 50); // Отбор по реквизиту

Запрос.УстановитьПараметр("ПараметрыОтбора", СтруктураПараметровОтбора);

Результат = Запрос.Выполнить().Выбрать();

При использовании структуры в качестве второго параметра метода СрезПоследних(), ключи структуры должны соответствовать именам полей регистра (измерений, ресурсов или реквизитов), по которым производится отбор. Значения структуры будут использоваться как значения отбора.

3. Дополнительный отбор в секции ГДЕ

После того как вы сформировали корректный срез последних с учетом всех необходимых условий в параметрах виртуальной таблицы, вы можете добавить дополнительные условия в секцию ГДЕ основного запроса. Это может быть полезно для фильтрации результатов по каким-либо ресурсам или реквизитам, которые не являются критически важными для формирования самого среза, но нужны для дальнейшей обработки. В этом случае, если запись не соответствует условию в ГДЕ, она просто будет отброшена из уже сформированного и корректного набора «последних» данных.


ВЫБРАТЬ
    СрезПоследних.Номенклатура,
    СрезПоследних.ТипЦен,
    СрезПоследних.Цена,
    СрезПоследних.НаценкаПроцент
ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
        &ДатаСреза,
        "Номенклатура = &ВыбраннаяНоменклатура"
    ) КАК СрезПоследних
ГДЕ
    СрезПоследних.Цена > &МинимальнаяЦена
    И СрезПоследних.НаценкаПроцент <= &МаксимальнаяНаценка

В этом примере мы формируем срез последних для выбранной номенклатуры, а уже потом из полученного набора отбираем только те записи, где цена больше минимальной и наценка меньше или равна максимальной. Здесь НаценкаПроцент используется в ГДЕ, но сам срез уже был сформирован для корректных измерений. Если бы НаценкаПроцент была критична для *формирования* среза, ее следовало бы включить во второй параметр СрезПоследних().

Применение в динамическом списке

В контексте динамического списка, где источником данных является запрос к СрезПоследних, рекомендуется передавать параметры отбора непосредственно в запрос, формирующий этот срез. Это можно сделать несколькими способами:

  1. Через параметры запроса динамического списка: Вы можете определить параметры в запросе динамического списка (например, &ПараметрНоменклатура) и затем в коде или в свойствах динамического списка (на закладке "Параметры") связать их с элементами формы или значениями.
  2. Изменение текста запроса: Если отбор очень сложный и зависит от множества условий, можно динамически формировать текст запроса для динамического списка, вставляя нужные условия в параметр СрезПоследних().

При использовании динамического списка, свойства "Отбор" самого списка также могут применяться. Однако, если вы добавляете отбор по реквизиту через стандартный механизм отбора динамического списка, это эквивалентно добавлению условия в секцию ГДЕ основного запроса динамического списка. В этом случае действует то же правило: сначала формируется срез, а затем из него отфильтровываются записи. Чтобы избежать ошибок, наиболее критичные условия по реквизитам, влияющие на определение "последней" записи, следует включать в параметры виртуальной таблицы СрезПоследних().

Когда "СрезПоследних" может не сработать

Мы также должны рассмотреть ситуации, когда использование СрезПоследних может привести к нежелательным результатам:

Выводы

Мы выяснили, что отбор по реквизитам в виртуальной таблице СрезПоследних не только возможен, но и необходим для получения корректных данных в ряде случаев. Критически важно применять условия отбора по реквизитам (и другим полям) непосредственно в параметрах виртуальной таблицы СрезПоследних(), чтобы сам срез формировался уже с учетом этих условий. Дополнительные условия в секции ГДЕ можно использовать для дальнейшей фильтрации уже полученного корректного среза, если эти условия не влияют на логику определения "последней" записи.

Следуя этим рекомендациям, мы сможем эффективно использовать СрезПоследних для отображения точных и актуальных данных в наших управляемых формах и динамических списках 1С:Предприятия.

← На главную