Как правильно сделать ссылку на элемент справочника в запросе 1С?

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

Часто при написании запросов в системе 1С:Предприятие возникает необходимость сравнить поле таблицы с конкретным элементом справочника. Начинающие разработчики часто пытаются использовать методы встроенного языка, такие как НайтиПоКоду() или НайтиПоНаименованию(), прямо внутри текста запроса. Однако такой подход приводит к ошибке синтаксиса. Разберем детально, почему это происходит и как правильно решить эту задачу несколькими способами.

Почему нельзя использовать методы поиска в запросе?

Для начала проанализируем ситуацию: почему конструкция Значение(Справочник.Склады.НайтиПоКоду("000000001")) не работает? Важно понимать, что язык запросов 1С — это декларативный язык, который при выполнении транслируется в SQL-выражение. Система управления базами данных (СУБД), будь то MS SQL Server или PostgreSQL, ничего не знает об объектах и методах встроенного языка 1С. Она оперирует таблицами и связями. Методы типа НайтиПоКоду() являются объектными, они работают на стороне сервера приложений 1С, а не в базе данных.

Функция ЗНАЧЕНИЕ() в запросе может работать только с теми данными, которые конфигуратор "знает" еще на этапе проектирования (перечисления, предопределенные элементы, пустые ссылки). Для динамического поиска элементов этот метод не подходит. Рассмотрим правильные альтернативы.

Способ 1: Использование параметров запроса (Рекомендуемый)

Наиболее правильным и универсальным способом является передача готовой ссылки в запрос через параметр. Рассмотрим по шагам, как это реализовать. Сначала мы находим нужную ссылку во встроенном языке, а затем передаем ее в объект Запрос.

Посмотрим на пример кода:


// 1. Находим ссылку во встроенном языке
СсылкаСклад = Справочники.Склады.НайтиПоКоду("000000001");

// 2. Создаем запрос и устанавливаем параметр
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ТоварыВРозницеОстатки.КоличествоОстаток КАК Остаток
    |ИЗ
    |	РегистрНакопления.ТоварыВРознице.Остатки КАК ТоварыВРозницеОстатки
    |ГДЕ
    |	ТоварыВРозницеОстатки.Склад = &НужныйСклад";

Запрос.УстановитьПараметр("НужныйСклад", СсылкаСклад);
РезультатЗапроса = Запрос.Выполнить();

Этот метод считается лучшим с точки зрения производительности. В этом случае СУБД сравнивает два простых идентификатора (GUID) внутри одной таблицы, что происходит максимально быстро.

Способ 2: Использование предопределенных элементов

Если склад, к которому вы обращаетесь, является системным и создается один раз на этапе разработки, его можно сделать предопределенным в конфигураторе. В этом случае вы можете обращаться к нему напрямую через функцию ЗНАЧЕНИЕ() без использования параметров.

Рассмотрим пример такого запроса:


ВЫБРАТЬ
    ВЫБОР 
        КОГДА ТоварыВРозницеОстатки.Склад = ЗНАЧЕНИЕ(Справочник.Склады.ОсновнойСклад)
            ТОГДА ТоварыВРозницеОстатки.КоличествоОстаток
        ИНАЧЕ 0
    КОНЕЦ КАК ОстатокПоОсновному
ИЗ
    РегистрНакопления.ТоварыВРознице.Остатки КАК ТоварыВРозницеОстатки

Важно: этот способ работает только для тех элементов, которые созданы в дереве конфигурации с уникальным именем (именем предопределенного данных).

Способ 3: Обращение через реквизиты (Код или Наименование)

Иногда программисты используют обращение через точку к коду элемента прямо в условии запроса. Выясним причину, почему это допустимо, но нежелательно.

Пример кода:


ВЫБРАТЬ
    ТоварыВРозницеОстатки.КоличествоОстаток
ИЗ
    РегистрНакопления.ТоварыВРознице.Остатки КАК ТоварыВРозницеОстатки
ГДЕ
    ТоварыВРозницеОстатки.Склад.Код = "000000001"

Проанализируем ситуацию с точки зрения СУБД. Когда вы пишете Склад.Код, система выполняет неявное левое соединение (LEFT JOIN) основной таблицы остатков с таблицей справочника «Склады». На больших объемах данных (сотни тысяч строк) это может существенно замедлить выполнение отчета. Кроме того, поиск по строковому полю всегда медленнее, чем по ссылочному полю.

Способ 4: Работа с уникальным идентификатором (GUID)

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

Разберем, как это сделать:


// Преобразуем строку в УникальныйИдентификатор и получаем ссылку
Идентификатор = Новый УникальныйИдентификатор("5d1a8e2b-2a2b-11eb-812d-00155d010c01");
СсылкаНаОбъект = Справочники.Склады.ПолучитьСсылку(Идентификатор);

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

Способ 5: Пустые ссылки в запросе

Часто в условиях ВЫБОР или ГДЕ требуется проверить поле на заполненность. Для этого также используется функция ЗНАЧЕНИЕ(), но со специальным ключом ПустаяСсылка. Это избавляет от необходимости передавать пустую ссылку через параметр.

Пример использования:


ВЫБРАТЬ
    ТоварыВРозницеОстатки.Номенклатура
ИЗ
    РегистрНакопления.ТоварыВРознице.Остатки КАК ТоварыВРозницеОстатки
ГДЕ
    ТоварыВРозницеОстатки.Склад = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)

Опасность «хардкода» кодов в запросах

Рассмотрим важный аспект сопровождения кода. Проверка Код = "000000001" считается плохим тоном в разработке 1С ("хардкодом"). Вот основные риски:

  1. Перекодирование: Если бухгалтер решит изменить префикс справочника или перекодировать элементы, ваш запрос перестанет работать.
  2. Перенос данных: При обмене данными или переносе в другую базу коды могут измениться или дополниться префиксами узлов.
  3. Читаемость: По коду "000000001" сложно понять, какой именно это склад, не заглядывая в базу.

Если вы не можете использовать предопределенный элемент, хорошей практикой считается создание настройки в константе или в специальном регистре сведений, где пользователь сам выберет нужный склад. В запросе вы просто прочитаете эту настройку и передадите ее в параметр.

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

← На главную