Как получить конкретную ссылку в запросе 1С и почему не работает ЗНАЧЕНИЕ() с поиском по коду

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

При написании запросов в платформе «1С:Предприятие 8.3» разработчики часто сталкиваются с необходимостью жестко зафиксировать или выбрать определенную ссылку на элемент справочника, документ или значение перечисления. На первый взгляд кажется, что для этого идеально подходит системная функция ЗНАЧЕНИЕ(). Однако при попытке написать конструкцию вроде поиска по коду внутри этой функции платформа выдает синтаксическую ошибку.

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

Принцип работы функции ЗНАЧЕНИЕ() и ее ограничения

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

Платформа должна сопоставить переданную строку с метаданными конфигурации и получить статический идентификатор. СУБД «ничего не знает» о метаданных 1С, она оперирует таблицами и уникальными идентификаторами (UUID). Функция ЗНАЧЕНИЕ() преобразует понятный нам путь к объекту конфигурации в бинарный идентификатор (GUID) в теле результирующего SQL-запроса.

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

Давайте вспомним полный список того, что компилятор 1С позволяет передавать в функцию ЗНАЧЕНИЕ():

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

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

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

Давайте разберем пример реализации этого способа на встроенном языке 1С. Сначала мы находим нужную нам ссылку во встроенном языке, а затем передаем ее в запрос в качестве параметра.


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

Если Не СсылкаНаПользователя.Пустая() Тогда

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

Этот способ идеален в 95% случаев, когда выполнение запроса происходит в программном коде, где у нас есть полный доступ к управлению параметрами.

Способ 2. Использование вложенных запросов (Когда нельзя передать параметр)

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

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

Давайте проанализируем, как будет выглядеть такой запрос:


ВЫБРАТЬ
	ЗаказПокупателя.Ссылка КАК Ссылка,
	// Получаем конкретную ссылку через подзапрос к справочнику Пользователи
	(ВЫБРАТЬ Ссылка ИЗ Справочник.Пользователи ГДЕ Код = "0001") КАК АдминистраторСистемы
ИЗ
	Документ.ЗаказПокупателя КАК ЗаказПокупателя

Важное предупреждение: Несмотря на кажущееся удобство, этот подход имеет существенные недостатки. Во-первых, если в пользовательском режиме администратор изменит код элемента (например, переименует код "0001" в "0001а"), ваш запрос молча вернет NULL, не вызывая явных ошибок компиляции, что существенно затруднит диагностику сбоя. Во-вторых, выполнение вложенных подзапросов для каждой строки выборки может негативно сказаться на производительности при работе с большими объемами данных.

Способ 3. Создание предопределенного элемента в конфигураторе

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

Рассмотрим порядок действий для настройки этого механизма:

  1. Откройте конфигурацию в режиме «Конфигуратор».
  2. Найдите нужный справочник (например, Справочники.Пользователи).
  3. Перейдите на вкладку «Прочее» и нажмите кнопку «Предопределенные».
  4. Добавьте новый предопределенный элемент, задав ему понятное имя (например, АдминистраторСистемы) и заполнив базовые реквизиты (Код, Наименование).
  5. Обновите конфигурацию базы данных.

После выполнения этих шагов элемент жестко связывается с метаданными по своему внутреннему уникальному идентификатору (UUID). Теперь мы можем абсолютно безопасно использовать функцию ЗНАЧЕНИЕ() напрямую в тексте любого запроса, не опасаясь изменения кодов пользователями в режиме «1С:Предприятие»:


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

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

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

← На главную