Часто при написании запросов в системе 1С:Предприятие возникает необходимость сравнить поле таблицы с конкретным элементом справочника. Начинающие разработчики часто пытаются использовать методы встроенного языка, такие как НайтиПоКоду() или НайтиПоНаименованию(), прямо внутри текста запроса. Однако такой подход приводит к ошибке синтаксиса. Разберем детально, почему это происходит и как правильно решить эту задачу несколькими способами.
Для начала проанализируем ситуацию: почему конструкция Значение(Справочник.Склады.НайтиПоКоду("000000001")) не работает? Важно понимать, что язык запросов 1С — это декларативный язык, который при выполнении транслируется в SQL-выражение. Система управления базами данных (СУБД), будь то MS SQL Server или PostgreSQL, ничего не знает об объектах и методах встроенного языка 1С. Она оперирует таблицами и связями. Методы типа НайтиПоКоду() являются объектными, они работают на стороне сервера приложений 1С, а не в базе данных.
Функция ЗНАЧЕНИЕ() в запросе может работать только с теми данными, которые конфигуратор "знает" еще на этапе проектирования (перечисления, предопределенные элементы, пустые ссылки). Для динамического поиска элементов этот метод не подходит. Рассмотрим правильные альтернативы.
Наиболее правильным и универсальным способом является передача готовой ссылки в запрос через параметр. Рассмотрим по шагам, как это реализовать. Сначала мы находим нужную ссылку во встроенном языке, а затем передаем ее в объект Запрос.
Посмотрим на пример кода:
// 1. Находим ссылку во встроенном языке
СсылкаСклад = Справочники.Склады.НайтиПоКоду("000000001");
// 2. Создаем запрос и устанавливаем параметр
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыВРозницеОстатки.КоличествоОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ТоварыВРознице.Остатки КАК ТоварыВРозницеОстатки
|ГДЕ
| ТоварыВРозницеОстатки.Склад = &НужныйСклад";
Запрос.УстановитьПараметр("НужныйСклад", СсылкаСклад);
РезультатЗапроса = Запрос.Выполнить();
Этот метод считается лучшим с точки зрения производительности. В этом случае СУБД сравнивает два простых идентификатора (GUID) внутри одной таблицы, что происходит максимально быстро.
Если склад, к которому вы обращаетесь, является системным и создается один раз на этапе разработки, его можно сделать предопределенным в конфигураторе. В этом случае вы можете обращаться к нему напрямую через функцию ЗНАЧЕНИЕ() без использования параметров.
Рассмотрим пример такого запроса:
ВЫБРАТЬ
ВЫБОР
КОГДА ТоварыВРозницеОстатки.Склад = ЗНАЧЕНИЕ(Справочник.Склады.ОсновнойСклад)
ТОГДА ТоварыВРозницеОстатки.КоличествоОстаток
ИНАЧЕ 0
КОНЕЦ КАК ОстатокПоОсновному
ИЗ
РегистрНакопления.ТоварыВРознице.Остатки КАК ТоварыВРозницеОстатки
Важно: этот способ работает только для тех элементов, которые созданы в дереве конфигурации с уникальным именем (именем предопределенного данных).
Иногда программисты используют обращение через точку к коду элемента прямо в условии запроса. Выясним причину, почему это допустимо, но нежелательно.
Пример кода:
ВЫБРАТЬ
ТоварыВРозницеОстатки.КоличествоОстаток
ИЗ
РегистрНакопления.ТоварыВРознице.Остатки КАК ТоварыВРозницеОстатки
ГДЕ
ТоварыВРозницеОстатки.Склад.Код = "000000001"
Проанализируем ситуацию с точки зрения СУБД. Когда вы пишете Склад.Код, система выполняет неявное левое соединение (LEFT JOIN) основной таблицы остатков с таблицей справочника «Склады». На больших объемах данных (сотни тысяч строк) это может существенно замедлить выполнение отчета. Кроме того, поиск по строковому полю всегда медленнее, чем по ссылочному полю.
Если у вас есть уникальный идентификатор элемента в виде строки (например, полученный из внешнего источника), вы не сможете преобразовать его в ссылку внутри самого запроса. Это необходимо сделать предварительно в коде 1С.
Разберем, как это сделать:
// Преобразуем строку в УникальныйИдентификатор и получаем ссылку
Идентификатор = Новый УникальныйИдентификатор("5d1a8e2b-2a2b-11eb-812d-00155d010c01");
СсылкаНаОбъект = Справочники.Склады.ПолучитьСсылку(Идентификатор);
// Передаем ссылку в запрос как параметр
Запрос.УстановитьПараметр("СкладСсылка", СсылкаНаОбъект);
Часто в условиях ВЫБОР или ГДЕ требуется проверить поле на заполненность. Для этого также используется функция ЗНАЧЕНИЕ(), но со специальным ключом ПустаяСсылка. Это избавляет от необходимости передавать пустую ссылку через параметр.
Пример использования:
ВЫБРАТЬ
ТоварыВРозницеОстатки.Номенклатура
ИЗ
РегистрНакопления.ТоварыВРознице.Остатки КАК ТоварыВРозницеОстатки
ГДЕ
ТоварыВРозницеОстатки.Склад = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
Рассмотрим важный аспект сопровождения кода. Проверка Код = "000000001" считается плохим тоном в разработке 1С ("хардкодом"). Вот основные риски:
Если вы не можете использовать предопределенный элемент, хорошей практикой считается создание настройки в константе или в специальном регистре сведений, где пользователь сам выберет нужный склад. В запросе вы просто прочитаете эту настройку и передадите ее в параметр.
Подведем итог: всегда старайтесь использовать параметры запроса для передачи ссылок на конкретные элементы. Это обеспечит максимальную производительность, надежность кода и его устойчивость к изменениям данных в базе.