Функция ВЫРАЗИТЬ в языке запросов 1С: приведение типов на живых примерах

· 9 мин

Содержание

ВЫРАЗИТЬ(<Выражение> КАК <Тип>) — функция языка запросов, которая приводит значение к нужному типу прямо внутри запроса. Тип указывают после слова КАК: Число(15, 2), Строка(100), Дата, Булево или ссылочный тип вроде Справочник.Номенклатура. Это не функция встроенного языка: в коде модуля она не работает , там для преобразований есть Число(), Строка() и ОписаниеТипов.

Нужна она в трёх случаях. Когда поле имеет составной тип и надо обратиться к реквизиту. Когда в ОБЪЕДИНИТЬ ВСЕ у колонок разные типы. Когда строка неограниченной длины мешает группировке или сравнению. Дальше по порядку, с работающими примерами.

Синтаксис ВЫРАЗИТЬ и правила приведения типов

Общая форма записи:

ВЫБРАТЬ
    ВЫРАЗИТЬ(Таблица.Поле КАК Строка(50)) КАК КороткоеПоле
ИЗ
    Справочник.Номенклатура КАК Таблица

Что можно указывать после КАК:

  • 🔢 Число(длина, точность) — например, Число(15, 2): всего 15 знаков, из них 2 после запятой;
  • 🔤 Строка(длина) — строка ограниченной длины; без длины получится строка неограниченной;
  • 📅 Дата — дата без уточнения состава в самом выражении;
  • ☑️ Булево;
  • 🔗 ссылочные типы: Справочник.Контрагенты, Документ.РеализацияТоваровУслуг, перечисления и т. д.

Правила, которые стоит держать в голове:

  1. Лишнее отбрасывается. Если в Число(15, 2) приводится значение с тремя знаками после запятой, оно округляется до двух. Если целая часть не помещается, запрос не упадёт молча, а выдаст ошибку или NULL — проверяйте разрядность с запасом.
  2. Строка обрезается справа до указанной длины. ВЫРАЗИТЬ("Ремонт компрессора" КАК Строка(6)) вернёт Ремонт.
  3. Приводить можно не всё ко всему. Число в строку и обратно — можно, число в ссылку на справочник — нельзя, запрос не пройдёт проверку.
  4. Для ссылок действует особое правило: если реальное значение не того типа, что указан в КАК, результат — 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

Передача таблицы в запрос

Таблицу значений можно передать параметром и поместить во временную таблицу:

Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ
    |    Т.Артикул КАК Артикул,
    |    Т.Сумма КАК Сумма
    |ПОМЕСТИТЬ ВТ_Загрузка
    |ИЗ
    |    &Таблица КАК Т";
Запрос.УстановитьПараметр("Таблица", Таблица);

Здесь типы колонок берутся из таблицы. Если колонка объявлена без типа, запрос получит составной тип, и ВЫРАЗИТЬ придётся ставить уже на этом этапе. Поэтому лучше типизировать колонки до передачи: тогда в запросе всё работает без лишних приведений.

Ошибки при работе с ВЫРАЗИТЬ и как их устранить

Ниже — ситуации, с которыми реально сталкиваются, и их решения.

Диагностика: выберите симптом

Если ошибка «Несоответствие типов» возникает на уровне модуля, а не запроса, смотрите на результат запроса: после ВЫРАЗИТЬ колонка может содержать NULL, а код ждёт число или строку.

Когда ВЫРАЗИТЬ не нужен: альтернативы

Не каждая задача с типами решается этой функцией. Подберите инструмент под ситуацию:

  • 🎯 Нужно проверить тип, а не привести. Используйте ТИПЗНАЧЕНИЯ(Поле) и оператор ССЫЛКА: ГДЕ Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг. Это дешевле и не создаёт соединений.
  • 📝 Нужен текст для вывода пользователю. Берите ПРЕДСТАВЛЕНИЕ(Ссылка), а не приведение к строке.
  • 📅 Нужна дата без времени. Тут пригодится НАЧАЛОПЕРИОДА(Дата, ДЕНЬ): она обнуляет время, а ВЫРАЗИТЬ тип даты не сужает.
  • 🔁 Приведение нужно в десятке запросов. Один раз сформируйте временную таблицу с правильными типами и работайте с ней.

Если запрос всё равно ругается на тип, раскройте его по частям: уберите всё, кроме проблемной колонки, и посмотрите, какой тип она получает. Часто причина находится на два уровня глубже, в подзапросе или в ОБЪЕДИНИТЬ ВСЕ, где колонку описали по-разному.

Скорость запроса: как не замедлить выборку

ВЫРАЗИТЬ сам по себе бесплатный, дорого стоят его последствия. Что действительно влияет на время:

  • ⏱️ Условие по выражению. ГДЕ ВЫРАЗИТЬ(Поле КАК Строка(10)) = &Значение не позволяет СУБД опереться на индекс по полю: она сначала вычисляет выражение для каждой строки. Если можно, фильтруйте по исходному полю, а приведение делайте в ВЫБРАТЬ.
  • 🔗 Доступ к реквизитам через ВЫРАЗИТЬ. Каждое обращение вида ВЫРАЗИТЬ(Регистратор КАК Документ.X).Реквизит — это соединение с таблицей документов. Три-четыре таких выражения в запросе по большому регистру тормозят сильнее, чем всё остальное вместе.
  • 📦 Работа во временных таблицах. Сначала отберите нужные строки (по периоду, по типу регистратора через ССЫЛКА) и поместите в ПОМЕСТИТЬ. Приведение типов делайте во втором запросе по уже урезанной таблице.
  • 🧮 Типы заранее. Если один и тот же ВЫРАЗИТЬ приходится писать в десятке мест, вынесите его в временную таблицу один раз и дальше обращайтесь к готовой колонке.

Сравните два подхода к отбору документов определённого вида:

// Медленнее: приведение до отбора
ВЫБРАТЬ ВЫРАЗИТЬ(Т.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент
ИЗ РегистрНакопления.Продажи КАК Т

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

Во втором варианте строки с другими регистраторами отсекаются сразу, и лишних соединений становится меньше.

Проверить реальную нагрузку можно в консоли запросов: она показывает время выполнения. Для большой базы сравните оба варианта на одном периоде — разница на миллионе строк обычно видна невооружённым глазом.

Перед запуском запроса с ВЫРАЗИТЬ
Выполнено: 0 / 5

Частые вопросы

Можно ли использовать ВЫРАЗИТЬ в коде модуля, а не в запросе?
Нет. Это конструкция языка запросов. В коде преобразуют значения функциями Число(), Строка(), Дата() или методом ПривестиЗначение у ОписаниеТипов.
Чем ВЫРАЗИТЬ отличается от ПРЕДСТАВЛЕНИЕ?
ПРЕДСТАВЛЕНИЕ возвращает текст для показа пользователю (наименование, название перечисления). ВЫРАЗИТЬ меняет тип самого значения и оставляет его пригодным для расчётов и соединений.
Что вернёт ВЫРАЗИТЬ, если значение нельзя привести?
Для ссылочных типов — NULL. Для числа, которое не помещается в заданную разрядность, запрос завершится ошибкой, поэтому закладывайте длину с запасом.
Нужно ли приводить поле, если тип у него один?
Нет, лишнее приведение только усложняет запрос. Оно оправдано для составных типов, неограниченных строк и выравнивания колонок в объединении.
Как узнать, какие типы лежат в составном поле?
Выведите ТИПЗНАЧЕНИЯ(Поле) с группировкой по нему: получите список реальных типов, и сразу видно, какие ВЫРАЗИТЬ писать.