Функция ВЫРАЗИТЬ в языке запросов 1С: приведение типов на живых примерах
Содержание
ВЫРАЗИТЬ(<Выражение> КАК <Тип>) — функция языка запросов, которая приводит значение к нужному типу прямо внутри запроса. Тип указывают после слова КАК: Число(15, 2), Строка(100), Дата, Булево или ссылочный тип вроде Справочник.Номенклатура. Это не функция встроенного языка: в коде модуля она не работает
, там для преобразований есть Число(), Строка() и ОписаниеТипов.
Нужна она в трёх случаях. Когда поле имеет составной тип и надо обратиться к реквизиту. Когда в ОБЪЕДИНИТЬ ВСЕ у колонок разные типы. Когда строка неограниченной длины мешает группировке или сравнению. Дальше по порядку, с работающими примерами.
Синтаксис ВЫРАЗИТЬ и правила приведения типов
Общая форма записи:
ВЫБРАТЬ
ВЫРАЗИТЬ(Таблица.Поле КАК Строка(50)) КАК КороткоеПоле
ИЗ
Справочник.Номенклатура КАК Таблица
Что можно указывать после КАК:
- 🔢
Число(длина, точность)— например,Число(15, 2): всего 15 знаков, из них 2 после запятой; - 🔤
Строка(длина)— строка ограниченной длины; без длины получится строка неограниченной; - 📅
Дата— дата без уточнения состава в самом выражении; - ☑️
Булево; - 🔗 ссылочные типы:
Справочник.Контрагенты,Документ.РеализацияТоваровУслуг, перечисления и т. д.
Правила, которые стоит держать в голове:
- Лишнее отбрасывается. Если в
Число(15, 2)приводится значение с тремя знаками после запятой, оно округляется до двух. Если целая часть не помещается, запрос не упадёт молча, а выдаст ошибку илиNULL— проверяйте разрядность с запасом. - Строка обрезается справа до указанной длины.
ВЫРАЗИТЬ("Ремонт компрессора" КАК Строка(6))вернётРемонт. - Приводить можно не всё ко всему. Число в строку и обратно — можно, число в ссылку на справочник — нельзя, запрос не пройдёт проверку.
- Для ссылок действует особое правило: если реальное значение не того типа, что указан в
КАК, результат —NULL, а не ошибка.
Новый запрос удобно прогонять в консоли запросов: она сразу показывает типы колонок результата и подсвечивает ошибку синтаксиса в строке КАК.
Три типовых приведения
| Задача | Выражение | Результат |
|---|---|---|
| Округлить сумму до копеек | ВЫРАЗИТЬ(Сумма КАК Число(15, 2)) | 1234,5678 → 1234,57 |
| Ограничить длину комментария | ВЫРАЗИТЬ(Комментарий КАК Строка(200)) | Остаются первые 200 символов |
| Получить реквизит из составного поля | ВЫРАЗИТЬ(Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент | Контрагент документа, для других документов — NULL |
Как достать реквизит из поля составного типа
Это самое частое применение. Поле Регистратор в регистре может быть ссылкой на любой документ, и обратиться к Регистратор.Контрагент напрямую нельзя: у разных документов реквизиты разные. ВЫРАЗИТЬ говорит запросу, какой тип смотреть.
ВЫБРАТЬ
Продажи.Регистратор КАК Документ,
ВЫРАЗИТЬ(Продажи.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент КАК Контрагент,
Продажи.СуммаОборот КАК Сумма
ИЗ
РегистрНакопления.Продажи.Обороты(&Начало, &Конец, Регистратор) КАК Продажи
Имена объектов здесь учебные: подставьте регистр и документ из своей базы. Для строк, где регистратор — другой документ, в колонке Контрагент окажется NULL. Если регистраторов несколько и реквизит у них общий, делают несколько ВЫРАЗИТЬ и склеивают через ЕСТЬNULL или ВЫБОР:
ЕСТЬNULL(
ВЫРАЗИТЬ(Т.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент,
ВЫРАЗИТЬ(Т.Регистратор КАК Документ.ВозвратТоваровОтПокупателя).Контрагент)
Тот же приём работает с полями составного типа в справочниках и документах: «Владелец», «Субконто», реквизит с типом «Любая ссылка».
Каждое такое выражение добавляет соединение с таблицей документа. На регистре в миллионы строк три ВЫРАЗИТЬ по разным документам заметно замедлят запрос — об этом в разделе про скорость.
NULL и пустые значения: что ВЫРАЗИТЬ делает с отсутствующими данными
В запросах нет значения Неопределено, там живёт NULL. Он появляется при левом соединении, когда справа не нашлось пары, и при неудачном приведении ссылки. Сам ВЫРАЗИТЬ NULL не лечит: NULL на входе — NULL на выходе. А вот у NULL есть полезная роль как заготовки типа.
Выравнивание колонок в ОБЪЕДИНИТЬ ВСЕ
В объединении колонки сопоставляются по порядку, и типы должны быть совместимы. Если в одном запросе колонка числовая, а в другом вы подставляете NULL как заглушку, платформа не угадает тип. Помогает явное приведение:
ВЫБРАТЬ
Номенклатура,
Количество,
ВЫРАЗИТЬ(NULL КАК Число(15, 2)) КАК Сумма
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Номенклатура,
Количество,
Сумма
ИЗ
РегистрНакопления.Закупки.Обороты
То же с пустой строкой: вместо "" заглушку для длинного текстового поля пишут как ВЫРАЗИТЬ("" КАК Строка(100)), чтобы длина колонки соответствовала соседним запросам.
Защита от NULL после соединения
Порядок такой: сначала привести тип, потом обернуть в ЕСТЬNULL:
ЕСТЬNULL(ВЫРАЗИТЬ(Т.Сумма КАК Число(15, 2)), 0)
Без обёртки в отчёте появятся пустые ячейки, а любая арифметика с NULL даст NULL: 100 + NULL — это NULL, не 100.
Сравнение с пустым значением
Проверку «ссылка не заполнена» пишут через ЕСТЬ NULL или сравнение с пустой ссылкой (&ПустаяСсылка в параметре). Конструкция ВЫРАЗИТЬ(... КАК ...) = NULL не работает: с NULL равенство не срабатывает никогда, нужен именно ЕСТЬ NULL.
Применение в запросах к базе: строки, суммы, группировка
Теперь про случаи, где без ВЫРАЗИТЬ запрос просто не соберётся.
Неограниченные строки
Реквизит типа «Строка неограниченной длины» (комментарии, дополнительные описания) нельзя использовать в СГРУППИРОВАТЬ ПО, УПОРЯДОЧИТЬ ПО, в условиях сравнения и в РАЗЛИЧНЫЕ. Платформа сообщит, что поле такого типа не допускается. Решение:
ВЫБРАТЬ РАЗЛИЧНЫЕ
ВЫРАЗИТЬ(Контрагенты.Комментарий КАК Строка(150)) КАК Комментарий
ИЗ
Справочник.Контрагенты КАК Контрагенты
Выбирайте длину по реальным данным, а не «с запасом на миллион»: слишком короткая обрежет различия, и две разные записи схлопнутся в одну.
Деньги и округление
Если суммы считаются умножением цены на количество, в результате может быть много знаков после запятой. Для отчёта сумму приводят к двум знакам:
ВЫРАЗИТЬ(Цена * Количество КАК Число(15, 2)) КАК Сумма
Пример с числами: цена 99,99, количество 3,333 — произведение 333,26667, после приведения получится 333,27. Сумма по строкам, посчитанная до округления и после, может расходиться на копейки; в регламентированной отчётности сверяйте с тем, как округляет документ-источник.
Условия с выбором
Приведение работает и внутри ВЫБОР, и в параметрах виртуальных таблиц. Но в ГДЕ по такому выражению индекс обычно не используется — это отдельная тема ниже.
Преобразование типов в таблицах значений
Здесь картина другая. ВЫРАЗИТЬ работает только в тексте запроса. У таблицы значений типы колонок задаются описанием, и приводят значения иначе.
Типизация колонок
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));
Таблица.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20)));
Теперь любая запись в колонку Сумма сама пройдёт через описание типов: строка "12,345" превратится в число, а лишние знаки после запятой отрежутся. Для ручного приведения значения у ОписаниеТипов есть метод ПривестиЗначение:
ОписаниеСуммы = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
Значение = ОписаниеСуммы.ПривестиЗначение("1234,567"); // 1234,57
Передача таблицы в запрос
Таблицу значений можно передать параметром и поместить во временную таблицу:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Т.Артикул КАК Артикул,
| Т.Сумма КАК Сумма
|ПОМЕСТИТЬ ВТ_Загрузка
|ИЗ
| &Таблица КАК Т";
Запрос.УстановитьПараметр("Таблица", Таблица);
Здесь типы колонок берутся из таблицы. Если колонка объявлена без типа, запрос получит составной тип, и ВЫРАЗИТЬ придётся ставить уже на этом этапе. Поэтому лучше типизировать колонки до передачи: тогда в запросе всё работает без лишних приведений.
Ошибки при работе с ВЫРАЗИТЬ и как их устранить
Ниже — ситуации, с которыми реально сталкиваются, и их решения.
ВЫРАЗИТЬ(Поле КАК Строка(150)). Длину подберите по максимальной фактической длине значений.ТИПЗНАЧЕНИЯ(Поле), какие типы встречаются, и добавьте нужные ВЫРАЗИТЬ в ЕСТЬNULL.Число(15, 2) округляет каждую строку отдельно. Если итог должен считаться от точных значений, приводите уже итоговую сумму, а не слагаемые.ВЫРАЗИТЬ(NULL КАК Число(15, 2)).Строка(n) меньше фактической. Увеличьте n или не приводите поле, если группировка не нужна.Если ошибка «Несоответствие типов» возникает на уровне модуля, а не запроса, смотрите на результат запроса: после ВЫРАЗИТЬ колонка может содержать NULL, а код ждёт число или строку.
Когда ВЫРАЗИТЬ не нужен: альтернативы
Не каждая задача с типами решается этой функцией. Подберите инструмент под ситуацию:
- 🎯 Нужно проверить тип, а не привести. Используйте
ТИПЗНАЧЕНИЯ(Поле)и операторССЫЛКА:ГДЕ Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг. Это дешевле и не создаёт соединений. - 📝 Нужен текст для вывода пользователю. Берите
ПРЕДСТАВЛЕНИЕ(Ссылка), а не приведение к строке. - 📅 Нужна дата без времени. Тут пригодится
НАЧАЛОПЕРИОДА(Дата, ДЕНЬ): она обнуляет время, аВЫРАЗИТЬтип даты не сужает. - 🔁 Приведение нужно в десятке запросов. Один раз сформируйте временную таблицу с правильными типами и работайте с ней.
Если запрос всё равно ругается на тип, раскройте его по частям: уберите всё, кроме проблемной колонки, и посмотрите, какой тип она получает. Часто причина находится на два уровня глубже, в подзапросе или в ОБЪЕДИНИТЬ ВСЕ, где колонку описали по-разному.
Скорость запроса: как не замедлить выборку
ВЫРАЗИТЬ сам по себе бесплатный, дорого стоят его последствия. Что действительно влияет на время:
- ⏱️ Условие по выражению.
ГДЕ ВЫРАЗИТЬ(Поле КАК Строка(10)) = &Значениене позволяет СУБД опереться на индекс по полю: она сначала вычисляет выражение для каждой строки. Если можно, фильтруйте по исходному полю, а приведение делайте вВЫБРАТЬ. - 🔗 Доступ к реквизитам через ВЫРАЗИТЬ. Каждое обращение вида
ВЫРАЗИТЬ(Регистратор КАК Документ.X).Реквизит— это соединение с таблицей документов. Три-четыре таких выражения в запросе по большому регистру тормозят сильнее, чем всё остальное вместе. - 📦 Работа во временных таблицах. Сначала отберите нужные строки (по периоду, по типу регистратора через
ССЫЛКА) и поместите вПОМЕСТИТЬ. Приведение типов делайте во втором запросе по уже урезанной таблице. - 🧮 Типы заранее. Если один и тот же
ВЫРАЗИТЬприходится писать в десятке мест, вынесите его в временную таблицу один раз и дальше обращайтесь к готовой колонке.
Сравните два подхода к отбору документов определённого вида:
// Медленнее: приведение до отбора
ВЫБРАТЬ ВЫРАЗИТЬ(Т.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент
ИЗ РегистрНакопления.Продажи КАК Т
// Быстрее: сначала отбор по типу, потом приведение
ВЫБРАТЬ ВЫРАЗИТЬ(Т.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент
ИЗ РегистрНакопления.Продажи КАК Т
ГДЕ Т.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
Во втором варианте строки с другими регистраторами отсекаются сразу, и лишних соединений становится меньше.
Проверить реальную нагрузку можно в консоли запросов: она показывает время выполнения. Для большой базы сравните оба варианта на одном периоде — разница на миллионе строк обычно видна невооружённым глазом.
Частые вопросы
Можно ли использовать ВЫРАЗИТЬ в коде модуля, а не в запросе?
Число(), Строка(), Дата() или методом ПривестиЗначение у ОписаниеТипов.Чем ВЫРАЗИТЬ отличается от ПРЕДСТАВЛЕНИЕ?
ПРЕДСТАВЛЕНИЕ возвращает текст для показа пользователю (наименование, название перечисления). ВЫРАЗИТЬ меняет тип самого значения и оставляет его пригодным для расчётов и соединений.Что вернёт ВЫРАЗИТЬ, если значение нельзя привести?
NULL. Для числа, которое не помещается в заданную разрядность, запрос завершится ошибкой, поэтому закладывайте длину с запасом.Нужно ли приводить поле, если тип у него один?
Как узнать, какие типы лежат в составном поле?
ТИПЗНАЧЕНИЯ(Поле) с группировкой по нему: получите список реальных типов, и сразу видно, какие ВЫРАЗИТЬ писать.