Значения в языке запросов 1С: литералы, параметры, ВЫБОР и временные таблицы
Содержание
Оператора присваивания в языке запросов 1С нет: нельзя написать Поле = 5 или завести переменную внутри текста запроса. Значение полю задают выражением в списке выборки с псевдонимом — ВЫБРАТЬ 5 КАК Количество, а значение «снаружи» передают параметром &Имя через Запрос.УстановитьПараметр(). В переменную встроенного языка результат попадает уже после выполнения — из выборки или таблицы значений.
Отсюда и путаница: разработчик ищет аналог SET или UPDATE, а их нет. Запрос в 1С только читает данные. Ниже — все рабочие способы получить в поле нужное значение: константу-литерал, параметр, ссылку на предопределённый элемент, результат условия, подстановку вместо NULL, значение из временной таблицы.
Как задать полю фиксированное значение: литералы, КАК и ЗНАЧЕНИЕ()
Любое выражение в списке ВЫБРАТЬ становится полем результата. Имя полю даёт ключевое слово КАК. Если псевдоним не указать, платформа назовёт поле сама (Поле1, Поле2), и обращаться к нему из кода будет неудобно.
ВЫБРАТЬ
Товары.Ссылка КАК Номенклатура,
1 КАК Количество,
"Без комментария" КАК Комментарий,
ИСТИНА КАК Отметка,
ДАТАВРЕМЯ(2025, 1, 1) КАК ДатаНачала,
NULL КАК Резерв
ИЗ
Справочник.Номенклатура КАК Товары
Какие литералы допустимы:
- 🔢 Число —
1,0.5,-100. Дробная часть отделяется точкой. - 🔤 Строка — в двойных кавычках:
"Склад". Кавычку внутри строки удваивают:"ООО ""Ромашка""". - 📅 Дата — функция
ДАТАВРЕМЯ(Год, Месяц, День)или с временемДАТАВРЕМЯ(2025, 1, 1, 23, 59, 59). - ✅ Булево —
ИСТИНАилиЛОЖЬ. - ⭕ Пустые значения —
NULLиНЕОПРЕДЕЛЕНО.
Пустые значения разных типов
Иногда полю нужно присвоить не NULL, а именно пустое значение своего типа. Это важно для объединений и для последующей обработки в коде, где NULL придётся проверять отдельно.
- Пустая строка —
"". - Пустое число —
0. - Пустая дата —
ДАТАВРЕМЯ(1, 1, 1), то есть 01.01.0001. - Пустая ссылка —
ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка), о ней ниже.
Ссылки, перечисления и предопределённые элементы
Ссылочное значение строкой не задашь. Для этого есть функция ЗНАЧЕНИЕ():
ВЫБРАТЬ
ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка) КАК Контрагент,
ЗНАЧЕНИЕ(Перечисление.ЮридическоеФизическоеЛицо.ЮридическоеЛицо) КАК ВидЛица,
ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход) КАК ВидДвижения
ЗНАЧЕНИЕ() принимает только то, что известно на этапе разбора текста: пустые ссылки, значения перечислений, предопределённые элементы справочников, планов счетов и планов видов характеристик, виды движений. Обычный элемент справочника («Основной склад», созданный пользователем) так не получить — его передают параметром.
Перечисления в примере взяты из типовых конфигураций. В своей базе проверьте имя перечисления в дереве конфигурации: ошибка в имени даёт исключение при выполнении запроса.
Значения констант
Константы читаются из таблицы Константы. Каждая константа там — отдельное поле:
ВЫБРАТЬ
Константы.ВалютаРегламентированногоУчета КАК Валюта
ИЗ
Константы КАК Константы
Имя константы бывает разным в разных конфигурациях — сверяйтесь с веткой «Константы» в конфигураторе. Если нужно подставить значение константы в каждую строку другой выборки, соедините таблицы или просто прочитайте константу в коде и передайте её параметром. Второй вариант обычно понятнее.
Параметры запроса: как передать значение переменной из кода
Параметр — это место в тексте запроса, куда при выполнении подставляется значение из встроенного языка. Обозначается амперсандом: &Дата, &Склад, &СписокТоваров.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура КАК Номенклатура,
| Остатки.КоличествоОстаток КАК Остаток,
| &Склад КАК Склад,
| &ДатаОтчета КАК ДатаОтчета
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&ДатаОтчета, Склад = &Склад) КАК Остатки";
Запрос.УстановитьПараметр("Склад", ВыбранныйСклад);
Запрос.УстановитьПараметр("ДатаОтчета", КонецДня(ТекущаяДатаСеанса()));
Результат = Запрос.Выполнить();
Имя регистра и измерения здесь условные — подставьте свои. Важно другое:
- Параметр работает не только в условии, но и в списке выборки. Строка
&Склад КАК Складприсваивает полю значение переменнойВыбранныйСкладв каждой строке результата. - Один параметр можно использовать в тексте сколько угодно раз — значение задаётся один раз.
- Имя в
УстановитьПараметр()пишется без амперсанда. - Если параметр есть в тексте, а значение не установлено, запрос упадёт с ошибкой о неустановленном параметре.
Списки и массивы в параметре
В параметр можно положить массив, список значений или таблицу значений и проверять вхождение через В:
ГДЕ
Товары.Ссылка В (&СписокТоваров)
Скобки вокруг параметра в условии В обязательны.
Как получить значение из запроса обратно в переменную
Тут присваивание и происходит — но уже во встроенном языке:
Выборка = Результат.Выбрать();
Если Выборка.Следующий() Тогда
ОстатокТовара = Выборка.Остаток;
Иначе
ОстатокТовара = 0;
КонецЕсли;
Для нескольких строк используют цикл Пока Выборка.Следующий() Цикл, для работы со всем набором — Результат.Выгрузить(), который возвращает таблицу значений. Проверка Результат.Пустой() до выборки экономит лишний обход.
Временные таблицы: значение из одного запроса в другой
Если значение нужно вычислить один раз и использовать в нескольких следующих запросах, его кладут во временную таблицу. Это ближайший аналог переменной внутри пакета запросов.
ВЫБРАТЬ
МАКСИМУМ(Цены.Период) КАК ДатаЦены
ПОМЕСТИТЬ ВТ_ПоследняяДата
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК Цены
;
////////////////////////////////////////////////////////////
ВЫБРАТЬ
Цены.Номенклатура КАК Номенклатура,
Цены.Цена КАК Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК Цены
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ПоследняяДата КАК ВТ
ПО Цены.Период = ВТ.ДатаЦены
Запросы пакета разделяются точкой с запятой. Строка из косых черт — просто комментарий, его вставляет конструктор для читаемости.
Передать таблицу значений в запрос
Частая задача: в коде уже есть таблица значений, и её надо соединить с данными базы. Таблицу передают параметром и сразу помещают во временную таблицу:
ВЫБРАТЬ
ТЗ.Номенклатура КАК Номенклатура,
ТЗ.Количество КАК Количество
ПОМЕСТИТЬ ВТ_Товары
ИЗ
&ТаблицаТоваров КАК ТЗ
Колонки такой таблицы значений должны быть типизированы. При создании колонки указывайте тип: ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число")). Без описания типов запрос выдаст ошибку, потому что платформа не знает, какие данные лежат в колонке.
Когда нужен менеджер временных таблиц
Временная таблица живёт, пока жив её менеджер. Внутри одного пакета менеджер создаётся неявно. Если таблица должна пережить запрос и пригодиться в следующем объекте Запрос, создайте менеджер явно:
МВТ = Новый МенеджерВременныхТаблиц;
Запрос1 = Новый Запрос;
Запрос1.МенеджерВременныхТаблиц = МВТ;
// ... Запрос1 создаёт ВТ_Товары ...
Запрос2 = Новый Запрос;
Запрос2.МенеджерВременныхТаблиц = МВТ;
// Запрос2 читает ВТ_Товары
Для больших временных таблиц, по которым потом соединяют, добавляйте ИНДЕКСИРОВАТЬ ПО Номенклатура после ПОМЕСТИТЬ. На десятке строк индекс не нужен, на сотнях тысяч он заметно ускоряет соединение.
Чтобы получить результат каждого запроса пакета, используйте Запрос.ВыполнитьПакет() — он вернёт массив результатов в порядке следования запросов.
Значение по условию: конструкция ВЫБОР
ВЫБОР — это «если» внутри запроса. Поле получает то значение, чьё условие выполнилось первым.
ВЫБРАТЬ
Остатки.Номенклатура КАК Номенклатура,
ВЫБОР
КОГДА Остатки.КоличествоОстаток <= 0
ТОГДА "Нет в наличии"
КОГДА Остатки.КоличествоОстаток < 10
ТОГДА "Мало"
ИНАЧЕ "Достаточно"
КОНЕЦ КАК Статус
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
Правила, которые стоит держать в голове:
- 🔀 Условия проверяются сверху вниз. Остаток 5 попадёт во вторую ветку, остаток 0 — в первую.
- ⚠️ Без
ИНАЧЕполе получитNULL, если ни одно условие не сработало. - 🧩 Ветки могут возвращать значения разных типов — поле станет составным. Для итогов и сравнений лучше, чтобы тип был один.
- 🔁
ВЫБОРможно вкладывать, использовать внутри агрегатных функций и в условияхГДЕ.
Условная сумма в одном проходе
Приём, который экономит лишние запросы: раскладка одной колонки на несколько через ВЫБОР внутри СУММА.
ВЫБРАТЬ
Продажи.Контрагент КАК Контрагент,
СУММА(ВЫБОР
КОГДА Продажи.Сумма > 0 ТОГДА Продажи.Сумма
ИНАЧЕ 0
КОНЕЦ) КАК Продано,
СУММА(ВЫБОР
КОГДА Продажи.Сумма < 0 ТОГДА -Продажи.Сумма
ИНАЧЕ 0
КОНЕЦ) КАК Возвращено
ИЗ
РегистрНакопления.Продажи КАК Продажи
СГРУППИРОВАТЬ ПО
Продажи.Контрагент
Если у контрагента строки на 1 000 и −200 рублей, получится «Продано» 1 000 и «Возвращено» 200.
NULL и типы: ЕСТЬNULL, ВЫРАЗИТЬ, ТИПЗНАЧЕНИЯ
NULL появляется в запросе чаще, чем кажется: при левом соединении, когда справа нет пары, при обращении к реквизиту через точку у пустой ссылки, в ВЫБОР без ИНАЧЕ. Арифметика с NULL даёт NULL: 100 + NULL — это не 100.
Подставить значение вместо NULL
Функция ЕСТЬNULL(Выражение, Замена) возвращает замену, если выражение равно NULL:
ВЫБРАТЬ
Товары.Ссылка КАК Номенклатура,
ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
ИЗ
Справочник.Номенклатура КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ПО Товары.Ссылка = Остатки.Номенклатура
Товары без остатка получат 0 вместо пустоты, и сумма по колонке посчитается корректно.
Не путайте функцию и оператор:
| Конструкция | Что делает | Где применять |
|---|---|---|
ЕСТЬNULL(Поле, 0) | Возвращает 0 вместо NULL | В списке выборки, в выражениях |
Поле ЕСТЬ NULL | Проверка, результат ИСТИНА/ЛОЖЬ | В ГДЕ, КОГДА, ИМЕЮЩИЕ |
Поле = NULL | Не работает как проверка | Не использовать |
Приведение типа через ВЫРАЗИТЬ
ВЫРАЗИТЬ(Выражение КАК Тип) сужает или задаёт тип значения. Три типичных случая:
- Строка неограниченной длины. Реквизиты вроде «Комментарий» нельзя сравнивать и группировать напрямую. Приведите к строке фиксированной длины:
ВЫРАЗИТЬ(Док.Комментарий КАК СТРОКА(200)). - Составной тип. У поля
Регистратормного возможных типов. Чтобы взять реквизит конкретного документа без лишних соединений, пишутВЫРАЗИТЬ(Движения.Регистратор КАК Документ.ПоступлениеТоваровУслуг).Номер. - Точность числа.
ВЫРАЗИТЬ(Цена * 1.2 КАК ЧИСЛО(15, 2))обрежет результат до двух знаков после запятой.
Проверка типа
Если поле составное, тип проверяют оператором ССЫЛКА или функцией ТИПЗНАЧЕНИЯ:
ВЫБОР
КОГДА Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
ТОГДА "Продажа"
ИНАЧЕ "Прочее"
КОНЕЦ КАК ВидОперации
Сравнение с типом: ТИПЗНАЧЕНИЯ(Поле) = ТИП(Справочник.Контрагенты).
Что не получится сделать запросом и как обойти
Здесь собраны ограничения, на которые натыкаются те, кто пришёл из SQL.
| Задача | Почему не выходит | Как сделать |
|---|---|---|
| Изменить данные в базе | Язык запросов только читает | Объект (ПолучитьОбъект()) или набор записей регистра, затем Записать() |
| Завести переменную в тексте запроса | Переменных нет | Параметр &Имя или временная таблица с одной строкой |
Получить обычный элемент справочника через ЗНАЧЕНИЕ() | Функция видит только предопределённые элементы | Передать ссылку параметром |
Склеить строку и число через + | Типы не приводятся автоматически | Собрать строку в коде после выборки |
| Вызвать функцию общего модуля в запросе | Встроенный язык в запросе не выполняется | Посчитать в коде, передать параметром или результат дописать в таблицу значений |
Ошибки, которые встречаются чаще всего
УстановитьПараметр() не совпадает с именем в тексте (опечатка, лишний амперсанд, латинская буква вместо кириллической). Или вызов стоит после Выполнить().ГДЕ, СГРУППИРОВАТЬ ПО или УПОРЯДОЧИТЬ ПО. Оберните его в ВЫРАЗИТЬ(Поле КАК СТРОКА(N)).ЕСТЬNULL(Поле, 0) к каждому полю правой таблицы.Новый ОписаниеТипов(...).МенеджерВременныхТаблиц. Создайте менеджер и присвойте его обоим запросам.0, "", NULL) в том же порядке.Если для «присвоения» данных в базе вы переходите от запроса к записи объектов, сначала проверьте обработку на копии базы. Массовая перезапись документов или наборов записей без проверки может испортить учёт за закрытые периоды.
Частые вопросы
Можно ли в запросе 1С использовать результат одного поля в другом поле той же выборки?
ВЫБРАТЬ нельзя использовать в соседнем поле того же запроса. Повторите выражение целиком или вынесите расчёт во временную таблицу и считайте во втором запросе пакета.Как подставить текущую дату в запрос?
Запрос.УстановитьПараметр("Дата", ТекущаяДатаСеанса()).Чем ЗНАЧЕНИЕ() отличается от параметра?
ЗНАЧЕНИЕ() вычисляется при разборе текста и подходит для предопределённых значений и пустых ссылок. Параметр подставляется при выполнении и принимает любое значение, в том числе обычный элемент справочника, дату или массив.Где задать параметры, если запрос собран конструктором?
УстановитьПараметр() после присвоения текста. Конструктор только формирует текст, значения он не хранит.Можно ли присвоить значение по умолчанию полю, которого нет в части объединения?
ОБЪЕДИНИТЬ ВСЕ, где поля нет, укажите на его месте литерал нужного типа с тем же псевдонимом, например 0 КАК Сумма или ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка) КАК Склад.