Как привести поле к числу оператором ВЫРАЗИТЬ в 1С 8.3
Содержание
Оператор приводит значение к нужному типу прямо в тексте запроса: ВЫРАЗИТЬ(Поле КАК ЧИСЛО(15, 2)). В скобках после ЧИСЛО указывают разрядность (сколько всего знаков) и точность (сколько знаков после запятой). Это единственный способ управлять типом и масштабом числа средствами самого запроса, не выходя во встроенный язык.
Сразу уберём частую путаницу. ВЫРАЗИТЬ в языке запросов 1С 8.3 — это не разбор текста. Он не превратит строку "123" в число 123. Его задача — вытащить значение конкретного типа из поля составного типа и ограничить разрядность, чтобы поле можно было группировать, соединять и упорядочивать. Ниже разберём синтаксис, поведение с дробной частью, влияние на производительность и когда вместо запроса лучше использовать функцию Число() во встроенном языке.
Синтаксис: как записать приведение к числу
Общая форма одинакова для всех типов:
ВЫРАЗИТЬ(<Выражение> КАК <Тип>)
Для числа тип записывается с двумя параметрами в скобках:
ВЫРАЗИТЬ(Таблица.Поле КАК ЧИСЛО(10, 2))
- Первое число — разрядность: общее количество значащих цифр, включая дробную часть.
10означает «до 10 цифр всего». - Второе число — точность: сколько из них приходится на дробную часть.
2— два знака после запятой.
То есть ЧИСЛО(10, 2) вмещает число вида 12345678.99: восемь знаков в целой части и два в дробной. Параметры можно не указывать — тогда платформа подберёт тип по контексту, но для группировок и соединений разрядность почти всегда нужна явно.
Разрядность указывают с запасом, но без излишка. Слишком большое значение не ускоряет запрос, а слишком маленькое приводит к переполнению при первом же крупном значении.
Приведение к ссылочному типу выглядит иначе — там в скобках не длина, а имя типа, например ВЫРАЗИТЬ(РегистрСведений.Цены.Регистратор КАК Документ.ПоступлениеТоваровУслуг). Но для числа параметры — это всегда пара «разрядность, точность».
У ВЫРАЗИТЬ общий синтаксис и для других типов: СТРОКА(150) ограничивает длину строки, ДАТА приводит к дате, БУЛЕВО — к логическому значению. Логика везде одинакова: оператор выбирает из составного типа значение нужного вида и задаёт его параметры. Число — частный, но самый востребованный случай, потому что именно по числам чаще всего группируют и считают итоги.
Главное заблуждение: строку «123» в число ВЫРАЗИТЬ не превращает
Это ошибка, на которую натыкаются почти все новички. В языке запросов нет функции разбора текста в число. Если в поле лежит строка "123", то ВЫРАЗИТЬ(Поле КАК ЧИСЛО(10, 0)) не вернёт 123.
Что произойдёт на самом деле, зависит от типа поля:
- 🔹 Поле составного типа содержит и число, и строку.
ВЫРАЗИТЬвернёт число только для тех записей, где фактически хранится число. Где лежит строка — вернётсяNULL. - 🔹 Поле типа Строка. Привести строку к числу запрос откажется — такое приведение не определено, и платформа выдаст ошибку синтаксиса или типов при компиляции.
Запомните формулу: ВЫРАЗИТЬ выбирает значение подходящего типа из составного поля, а не разбирает символы. Для несовпадающих записей результат — NULL, а не ноль и не исключение.
Если задача именно в том, чтобы разобрать текст с цифрами, делайте это после выборки, во встроенном языке:
Значение = Число(СтрокаСЦифрами);
Функция Число() работает с одним значением за раз и уже вне запроса. В запросе такой разбор недоступен ни через ВЫРАЗИТЬ, ни через другие операторы.
Если число из строки нужно регулярно и именно в запросах (для отбора, группировки, соединения), правильное решение — не искать обходной путь в тексте запроса, а завести отдельный числовой реквизит и заполнять его при записи объекта. Денормализация здесь оправдана: один раз разобрали строку в число во встроенном языке, сохранили в реквизит — и дальше запрос работает с готовым числом быстро и без NULL.
Разрядность и точность: дробные числа и масштаб
Когда поле уже числовое, ВЫРАЗИТЬ управляет его масштабом. Это нужно в двух случаях: привести разные колонки к единому типу (например, перед объединением запросов) и ограничить дробную часть.
Сокращение точности меняет значение. Если привести число 12.349 к ЧИСЛО(10, 2), в результате останется два знака после запятой. Платформа приводит значение к указанной точности, поэтому перед таким приведением проверяйте, не теряете ли вы значащие копейки. Когда важен строгий способ округления, округляйте явно функцией Окр() во встроенном языке, а не полагайтесь на усечение в запросе.
Чтобы было нагляднее, как разрядность и точность влияют на результат:
| Исходное значение | Приведение | Результат |
|---|---|---|
12.349 | ЧИСЛО(10, 2) | число с двумя знаками после запятой |
12.349 | ЧИСЛО(10, 0) | дробная часть отбрасывается |
1250.50 | ЧИСЛО(15, 2) | значение сохраняется полностью |
123456 | ЧИСЛО(3, 0) | ошибка переполнения разрядности |
Последняя строка — самая частая причина падения отчёта в проде: на тестовых данных суммы небольшие, разрядности ЧИСЛО(5, 2) хватает, а на реальной базе появляются миллионы, и запрос падает. Поэтому разрядность берут от максимально возможного значения реквизита, а не от того, что видно в демо-базе.
Если целая часть не помещается в заданную разрядность, запрос падает с ошибкой переполнения. Например, значение 123456 не влезет в ЧИСЛО(3, 0). Разрядность должна покрывать максимально ожидаемое число, а не среднее.
Отдельно про суммы и количество. Для денежных полей обычная пара — ЧИСЛО(15, 2), для количества с дробной частью — ЧИСЛО(15, 3). Это ориентиры: смотрите, какая разрядность задана у реквизита в конфигураторе, и не делайте в запросе меньше, чем хранится в базе.
Производительность: составные типы, поля неограниченной длины и индексы
У ВЫРАЗИТЬ есть вторая, не менее важная роль — техническая. Поля составного типа и поля неограниченной длины нельзя напрямую использовать в СГРУППИРОВАТЬ ПО, УПОРЯДОЧИТЬ ПО, в условиях соединения и в РАЗЛИЧНЫЕ. Платформа не знает, как сравнивать значения разных типов между собой.
ВЫРАЗИТЬ снимает это ограничение: приводит поле к одному конкретному типу фиксированной разрядности, и после этого его можно группировать и соединять.
ВЫБРАТЬ
ВЫРАЗИТЬ(Продажи.Измерение КАК ЧИСЛО(15, 2)) КАК Сумма,
Продажи.Контрагент
ИЗ
РегистрНакопления.Продажи КАК Продажи
СГРУППИРОВАТЬ ПО
Продажи.Контрагент,
ВЫРАЗИТЬ(Продажи.Измерение КАК ЧИСЛО(15, 2))
То же касается соединений. Нельзя связать таблицы по полю составного типа напрямую — платформа не умеет сравнивать значения разных типов в условии ПО. Приводят обе стороны к одному числовому типу:
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Ставки КАК Ставки
ПО ВЫРАЗИТЬ(Ставки.Код КАК ЧИСЛО(10, 0)) = Номенклатура.КодЧислом
Теперь о скорости. Само приведение к числу дёшево. Но есть нюанс с индексами:
- Если поле уже числовое и по нему есть индекс,
ВЫРАЗИТЬв условииГДЕможет помешать серверу использовать индекс — в условиях приводить такое поле не нужно. - Если поле составного типа, то отбор по конкретному типу через
ВЫРАЗИТЬвГДЕ, наоборот, помогает платформе сузить выборку.
Практический вывод: приводите тип там, где это обязательно (группировка, соединение, объединение разнотипных колонок), и не оборачивайте в ВЫРАЗИТЬ поля, которые и так нужного типа.
Ещё одна типичная проблема — поля неограниченной длины в соединениях. Строковый реквизит неограниченной длины запрос откажется использовать в условии ПО или в СГРУППИРОВАТЬ ПО. Приведение ВЫРАЗИТЬ(Поле КАК СТРОКА(150)) ограничивает длину и снимает запрет. С числами такого ограничения по длине нет, но принцип тот же: платформа требует заранее известного, фиксированного типа, чтобы строить сравнение и хеширование значений.
ВЫРАЗИТЬ в запросе или Число() в коде — что выбрать
Оба инструмента называют «преобразованием в число», но решают разные задачи.
| Способ | Когда применять | Ограничения |
|---|---|---|
ВЫРАЗИТЬ(... КАК ЧИСЛО(n, m)) в запросе | Достать число из составного поля; задать разрядность для группировки, соединения, объединения | Не разбирает строку в число; слишком малая разрядность → переполнение |
Число(Значение) во встроенном языке | Разобрать строку с цифрами уже после выборки, обработать одно значение | Работает построчно, вне запроса; на больших выборках медленнее |
Правило простое. Нужно, чтобы само поле запроса имело числовой тип и участвовало в агрегатах — это ВЫРАЗИТЬ. Нужно превратить текст в число — это Число() в коде, после того как запрос вернул результат.
Частый компромисс на больших отчётах: тяжёлую выборку делает запрос, а разбор строковых значений в числа — короткий цикл по результату уже во встроенном языке. Так сервер базы данных не нагружается тем, чего он всё равно не умеет, а разбор идёт только по тем строкам, что реально попали в отчёт. Переносить же числовую арифметику из запроса в цикл, наоборот, не стоит — агрегаты сервер считает быстрее.
Примеры: отчёты, объединение запросов и СКД
Единый тип при объединении. Когда два запроса объединяются через ОБЪЕДИНИТЬ, колонки на одной позиции должны быть совместимы. Если в одном запросе сумма имеет разрядность ЧИСЛО(15, 2), а в другом считается как разница, приведите обе к одному типу ВЫРАЗИТЬ(... КАК ЧИСЛО(15, 2)), иначе итоговая колонка получит составной числовой тип и может вести себя неожиданно в итогах.
Извлечение значения из регистра сведений. В регистрах с ресурсом или измерением составного типа отбор только по числовым записям делают так:
ВЫБРАТЬ
ВЫРАЗИТЬ(Параметры.Значение КАК ЧИСЛО(15, 4)) КАК ЧисловоеЗначение
ИЗ
РегистрСведений.Параметры КАК Параметры
ГДЕ
ВЫРАЗИТЬ(Параметры.Значение КАК ЧИСЛО(15, 4)) ЕСТЬ НЕ NULL
Условие ЕСТЬ НЕ NULL отсеивает записи, где в поле лежит не число.
СКД. В системе компоновки данных ВЫРАЗИТЬ используют в вычисляемых полях и в запросе набора данных ровно так же. Если поле ресурса имеет составной тип, без приведения СКД не даст по нему посчитать сумму или среднее — колонка окажется недоступна для агрегатных функций.
Отбор только числовых записей. Когда в журнале или регистре перемешаны значения разных типов, а посчитать нужно только числовые, приведение в паре с проверкой на NULL работает как фильтр. Записи, где лежит не число, дают NULL и не попадают в агрегат — функция СУММА их просто игнорирует. Это удобнее, чем выстраивать цепочку условий по типу значения.
Общий принцип по всем примерам один: ВЫРАЗИТЬ нужен там, где поле должно вести себя как число — участвовать в группировке, соединении, объединении или агрегате. Для вывода на форму или в макет, где тип уже числовой, лишнее приведение только усложняет текст запроса.
Чем отличается ВЫРАЗИТЬ от функции Число() во встроенном языке?
ВЫРАЗИТЬ действует внутри запроса и приводит тип уже существующего числа (или достаёт число из составного типа). Число() работает вне запроса, построчно, и умеет разбирать строку с цифрами. Для разбора текста подходит только Число().Почему ВЫРАЗИТЬ возвращает NULL?
ВЫРАЗИТЬ отдаёт значение только указанного типа, остальное превращает в NULL. Это не ошибка, а нормальное поведение.Что означают числа в ЧИСЛО(10, 2)?
ЧИСЛО(10, 2) вмещает до восьми цифр в целой части и две в дробной.Можно ли привести к числу без указания разрядности?
ВЫРАЗИТЬ(Поле КАК ЧИСЛО) допустимо, но для группировок, соединений и объединения запросов разрядность лучше задавать явно — иначе платформа подберёт тип по контексту, и результат бывает непредсказуемым.Почему запрос падает с ошибкой переполнения?
ЧИСЛО(5, 2) используйте ЧИСЛО(15, 2), если суммы бывают больше.