При работе с языком запросов «1С:Предприятие 8» разработчики часто сталкиваются с необходимостью использования значений констант. На первый взгляд кажется логичным использовать оператор ЗНАЧЕНИЕ(), по аналогии с перечислениями или предопределенными элементами. Однако при попытке написать ЗНАЧЕНИЕ(Константа.ВалютаУчета) система выдаст ошибку. В этой статье мы подробно разберем, почему так происходит, и рассмотрим все существующие способы получения констант в запросе.
Для начала проанализируем природу оператора ЗНАЧЕНИЕ() (в англоязычном варианте — VALUE()). Этот оператор предназначен исключительно для обращения к объектам, которые жестко зафиксированы в метаданных конфигурации на этапе разработки. К ним относятся:
ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка).Булево (ИСТИНА, ЛОЖЬ), типы цен и т.д.Выясним причину проблемы с константами: в отличие от вышеперечисленных объектов, константа — это не элемент метаданных в чистом виде, а данные. В конфигураторе мы определяем только структуру (имя и тип), а само значение хранится в базе данных. Платформа не знает, какое значение примет константа в конкретной информационной базе, поэтому запрос не может «подставить» её значение на этапе компиляции, как он делает это с GUID предопределенного элемента.
Кроме того, как справедливо отмечено в обсуждении, константа может иметь составной тип данных. Это делает невозможным её использование через оператор ЗНАЧЕНИЕ(), который требует однозначного определения типа и ссылки еще до обращения к таблицам БД.
Это классический метод, который часто встречается в типовых конфигурациях (например, в ERP или УТ 11). Мы можем обратиться к виртуальной таблице Константы, которая содержит все константы базы в виде полей одной (виртуальной) строки. Рассмотрим, как это реализовано на практике.
Для получения значения нам необходимо выполнить ЛЕВОЕ СОЕДИНЕНИЕ с таблицей Константы по условию ИСТИНА. Проанализируем пример кода:
ВЫБРАТЬ
Продажи.Номенклатура КАК Номенклатура,
Продажи.Количество КАК Количество,
Константы.ВалютаРегламентированногоУчета КАК Валюта
ИЗ
РегистрНакопления.Продажи КАК Продажи
ЛЕВОЕ СОЕДИНЕНИЕ Константы КАК Константы
ПО (ИСТИНА)
Важный нюанс: в современных версиях платформы (начиная с 8.2.14) физически каждая константа хранится в своей отдельной таблице (например, _Const1, _Const2). Это было сделано для оптимизации блокировок. Однако для удобства разработчиков 1С сохранила виртуальную таблицу Константы, обращение к которой платформа автоматически преобразует в нужные соединения на уровне SQL. При использовании этого метода стоит помнить, что если константа имеет составной тип, лучше использовать функцию ВЫРАЗИТЬ(), чтобы оптимизировать план выполнения запроса:
ВЫБРАТЬ
ВЫРАЗИТЬ(Константы.ОсновнойСклад КАК Справочник.Склады) КАК Склад
ИЗ
Константы КАК Константы
В большинстве случаев использование таблицы констант в сложном запросе — не самое лучшее решение с точки зрения производительности. Проанализируем ситуацию: если запрос обрабатывает тысячи строк, соединение с таблицей констант будет происходить для каждой строки, что может нагрузить оптимизатор СУБД.
Рассмотрим более элегантный и производительный способ: получение значения в коде 1С и передача его в запрос как параметра. Это исключает лишние соединения таблиц внутри SQL-запроса.
// Получаем значение константы программно
ВалютаУчета = Константы.ВалютаРегламентированногоУчета.Получить();
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.СуммаОстаток КАК Сумма
|ИЗ
| РегистрНакопления.Взаиморасчеты.Остатки( , Валюта = &ПарамВалюта) КАК Остатки";
Запрос.УстановитьПараметр("ПарамВалюта", ВалютаУчета);
Результат = Запрос.Выполнить();
Преимущества этого метода:
JOIN с таблицами констант.Существует еще один способ, который позволяет получить значение константы без явного прописывания соединений в секции СВЯЗИ. Это использование подзапроса прямо в полях выбора. Рассмотрим этот вариант:
ВЫБРАТЬ
Документ.Номер КАК Номер,
Документ.Дата КАК Дата,
(ВЫБРАТЬ ВалютаРегламентированногоУчета ИЗ Константы) КАК Валюта
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ
ГДЕ
Документ.Ссылка = &Ссылка
Такой подход удобен, когда значение константы нужно получить «точечно» и вы не хотите загромождать структуру связей основного запроса. Однако помните, что на уровне СУБД это все равно приведет к обращению к таблице констант. Для быстрой отладки и проверки подобных конструкций запросов можно использовать консоль запросов для управляемых форм.
Разберем, почему в старых темах на форумах часто обсуждают «удобство» или «неудобство» работы с константами. В версии 8.0 и 8.1 все константы хранились в одной строке одной таблицы. Это означало, что любое изменение любой константы блокировало всю таблицу целиком. Если один бухгалтер менял префикс организации, другой не мог в это время провести документ, требующий чтения константы «Способ оценки МПЗ».
Сейчас, когда каждая константа живет в своей таблице, использование их в запросах стало безопаснее. Тем не менее, хорошим тоном считается получение констант через параметры, если только вы не пишете сложный отчет на СКД, где доступ к таблице Константы может быть более удобным для настройки пользовательских полей. Для интерактивного тестирования таких запросов и работы с СКД подойдёт инженерная консоль запросов и отчетов СКД.
Проанализировав все варианты, мы можем дать следующие рекомендации:
Запрос.УстановитьПараметр), если вы вызываете запрос из программного кода. Это стандарт индустрии.ВЫРАЗИТЬ() для констант составного типа, чтобы избежать лишних соединений на уровне SQL и ускорить работу запроса.Таким образом, хотя оператор ЗНАЧЕНИЕ() не поддерживает константы, платформа предоставляет гибкие альтернативы для эффективной работы с этими данными.