При разработке отчетов и обработок в платформе 1С:Предприятие часто возникает задача получить актуальные цены номенклатуры из регистра сведений по строго определенному виду цен. Разберем особенности фильтрации данных в виртуальных таблицах, выясним ограничения языка запросов при работе с непредопределенными элементами справочников и рассмотрим оптимальные варианты решения этой задачи.
В языке запросов 1С существует специальная конструкция ЗНАЧЕНИЕ(), которая позволяет обращаться к предопределенным элементам конфигурации, значениям перечислений или системным типам данных напрямую в тексте запроса без передачи внешних параметров. Например, для предопределенного вида цены можно написать:
ГДЕ
ВидЦен = ЗНАЧЕНИЕ(Справочник.ВидыЦен.Оптовая)
Однако если элементы справочника ВидыЦен созданы пользователями в режиме предприятия и не являются предопределенными в дереве метаданных конфигуратора, обратиться к ним через ЗНАЧЕНИЕ() на уровне синтаксиса платформы невозможно.
Посмотрим на основные способы получения цен по конкретному непредопределенному виду цены.
Наиболее правильным, производительным и надежным подходом является предварительное получение ссылки на нужный элемент справочника в программном коде с последующей передачей ее в качестве параметра запроса.
Разберем по шагам реализацию этого метода:
НайтиПоКоду(), НайтиПоНаименованию() или считываем значение из константы/настройки.СрезПоследних.Посмотрим на пример программного кода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Цены.Номенклатура КАК Номенклатура,
| Цены.Цена КАК Цена
|ИЗ
| РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ВидЦен = &НужныйВидЦен) КАК Цены";
// Поиск ссылки на элемент справочника
СсылкаВидЦены = Справочники.ВидыЦен.НайтиПоКоду("000000022");
Запрос.УстановитьПараметр("Период", ТекущаяДата());
Запрос.УстановитьПараметр("НужныйВидЦен", СсылкаВидЦены);
РезультатЗапроса = Запрос.Выполнить();
Важный момент: обратите внимание на условие ВидЦен = &НужныйВидЦен. Оно должно располагаться именно внутри круглых скобок параметров виртуальной таблицы СрезПоследних(&Период, Условие), а не в секции ГДЕ основного запроса. Если вынести отбор в секцию ГДЕ, платформа сначала рассчитает срез последних по всем записям всех видов цен, и только затем применит фильтр. Это вызовет существенное падение производительности и может вернуть неактуальные данные.
Если требуется минимизировать код на встроенном языке и передать значение строкой прямо в теле запроса, синтаксис 1С позволяет обратиться к реквизиту измерения через точку:
ВЫБРАТЬ
Цены.Номенклатура КАК Номенклатура,
Цены.Цена КАК Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ВидЦен.Код = "000022") КАК Цены
Проанализируем специфику данного подхода:
ВидЦен.Код) СУБД выполняет неявное левое соединение (LEFT JOIN) с таблицей справочника до вычисления среза последних, что на больших объемах данных увеличивает нагрузку на сервер.Еще один вариант — получение ссылки на вид цен с помощью подзапроса непосредственно в параметрах виртуальной таблицы:
ВЫБРАТЬ
Цены.Номенклатура КАК Номенклатура,
Цены.Цена КАК Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
&Период,
ВидЦен В (
ВЫБРАТЬ ПЕРВЫЕ 1
Спр.Ссылка
ИЗ
Справочник.ВидыЦен КАК Спр
ГДЕ
Спр.Код = "000022"
)
) КАК Цены
Этот способ позволяет изолировать выборку ссылки внутри самого запроса, однако стандартная передача параметра Запрос.УстановитьПараметр() остается более прозрачной и предпочтительной для оптимизации СУБД.
Рассмотрим частый сопутствующий вопрос: можно ли получить фактическую себестоимость номенклатуры из регистра сведений ЦеныНоменклатуры, не указывая вид цены?
ЦеныНоменклатуры хранятся исключительно статические прайсовые или расчетные цены (включая вид цены с наименованием «Себестоимость», если он заведен вручную).СебестоимостьТоваров, ПартииТоваровНаСкладах, ВыручкаИСебестоимостьПродаж в конфигурациях ERP, КА, УТ или Запасы в УНФ) либо на счетах бухгалтерского учета (счета 41, 43 в регистре бухгалтерии Хозрасчетный в 1С:Бухгалтерии). Получать учетную себестоимость из регистра сведений цен методически некорректно.