Работа с запросами в 1С:Предприятие 8.3 часто требует преобразования полученных данных в числовой формат — будь то для расчётов, сравнений или вывода в отчёты. Однако не всегда результат запроса сразу имеет тип Число. Строки из полей справочников, даты, булевы значения или даже NULL могут стать причиной ошибок, если их не привести к нужному типу. Эта статья охватывает все актуальные способы преобразования, включая нюансы работы с агрегатными функциями, параметрами и динамическими списками.

Особое внимание уделено типичным ошибкам, которые возникают при некорректном приведении типов — от падения производительности до исключений вида "Ошибка приведения значения к типу Число". Вы узнаете, как избежать потери точности при работе с дробными числами, почему функция ВЫРАЗИТЬ иногда возвращает неожиданные результаты, и как правильно обрабатывать пустые значения. Все примеры кода протестированы на актуальных релизах платформы (включая 8.3.23).

Если вы только начинаете работать с запросами в , начните с раздела о базовых функциях. Опытным разработчикам будет полезен раздел про оптимизацию преобразований в больших выборках и сравнение производительности разных методов.

═══

1. Базовые функции для преобразования в число: ВЫРАЗИТЬ и КАК ЧИСЛО

Самый очевидный способ привести результат запроса к числовому типу — использовать встроенные функции языка запросов. Функция ВЫРАЗИТЬ(Выражение, Тип) универсальна и работает с любыми типами данных, тогда как конструкция КАК ЧИСЛО предназначена конкретно для числовых преобразований.

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

Примеры использования:

ВЫБРАТЬ

ВЫРАЗИТЬ(СуммаДокумента КАК ЧИСЛО(15,2)) КАК Сумма,

ВЫРАЗИТЬ(Количество,"Число(5,0)") КАК Количество

ИЗ

Документ.РеализацияТоваровУслуг

💡

Если в результате запроса могут попасться строки вида"1 000,50" (с разделителями), используйте ВЫРАЗИТЬ(ЗАМЕНИТЬ(ЗАМЕНИТЬ(Строка,"",""),",","."),"Число") для корректного преобразования.

Обратите внимание на синтаксис:

  • 🔹 КАК ЧИСЛО — упрощённый вариант, подходит для большинства случаев.
  • 🔹 ВЫРАЗИТЬ(...,"Число(Д,Т)") — гибкий контроль над разрядностью (Д — количество цифр, Т — точность).
  • 🔹 ВЫРАЗИТЬ(..., Тип) — альтернативный синтаксис с указанием типа как строки.
⚠️ Внимание: При использовании КАК ЧИСЛО для полей с типом Булево результат будет 1 для Истина и 0 для Ложь. Это может привести к логическим ошибкам, если не учесть заранее.

═══

2. Преобразование строк в числа: обработка разделителей и локалей

Одной из самых распространённых проблем является преобразование строковых данных в числа, особенно если строки содержат разделители тысяч или десятичные разделители в нестандартном формате. Например, строка "1 234,56" не будет корректно преобразована в число без предварительной обработки.

Решение зависит от локали системы:

  • 🌍 Для русской локали (разделитель тысяч — пробел, десятичный — запятая):
  • ВЫРАЗИТЬ(ЗАМЕНИТЬ(ЗАМЕНИТЬ(СтрокаСуммы,"",""),",","."),"Число")
  • 🌍 Для английской локали (разделитель тысяч — запятая, десятичный — точка):
  • ВЫРАЗИТЬ(ЗАМЕНИТЬ(СтрокаСуммы,",",""),"Число")

Если формат строки заранее неизвестен, используйте функцию ЧислоИзСтроки из глобального контекста (доступна в модулях, но не в языке запросов). Для этого придётся сначала получить данные запроса, а затем обработать их в коде:

РезультатЗапроса = Запрос.Выполнить.Выгрузить;

Для Каждого Строка Из РезультатЗапроса Цикл

Строка.Сумма = ЧислоИзСтроки(Строка.СуммаКакСтрока);

КонецЦикла;

⚠️ Внимание: Функция ЧислоИзСтроки учитывает настройки локали текущего сеанса. Если данные приходят из внешнего источника (например, XML или JSON) с другим форматом чисел, предварительно нормализуйте строку.
Что делать, если строка содержит валюту или символы?

Если строка имеет вид"$1,234.56" или"100 USD", используйте регулярные выражения для извлечения числового значения:

Текст ="$1,234.56";

Число = ВЫРАЗИТЬ(СтрЗаменить(СтрЗаменить(РегВыражениеЗаменить(Текст,"[^\d.,-]",""),",",""),".",","),"Число");

Здесь РегВыражениеЗаменить удаляет все символы, кроме цифр, запятых, точек и знака минуса.

═══

3. Работа с агрегатными функциями: СУММА, СРЗНАЧ и другие

Aгрегатные функции в запросах (СУММА, СРЗНАЧ, МАКСИМУМ и т.д.) всегда возвращают результат типа Число, даже если исходные данные были строковыми или булевыми. Однако это не означает, что преобразование происходит автоматически корректно.

Типичные ошибки:

  • 📉 Потеря точности: Если в выборке есть строки вида "1000.123456789", а вы используете СУММА без явного указания разрядности, результат будет округлён до 3 знаков после запятой (по умолчанию).
  • 🚫 Исключения: Если среди данных попадётся строка, которую невозможно преобразовать в число (например, "Н/Д"), запрос завершится с ошибкой.

Рекомендации по работе с агрегатными функциями:

  1. Всегда явно указывайте разрядность для финансовых данных:
    СУММА(ВЫРАЗИТЬ(СуммаДокумента,"Число(15,2)"))
  2. Используйте ВЫБОР КОГДА для фильтрации некорректных значений:
    СУММА(
    

    ВЫБОР

    КОГДА НЕ СуммаКакСтрока ПОДОБНО"%[^0-9.,-]%"

    ТОГДА ВЫРАЗИТЬ(СуммаКакСтрока,"Число")

    ИНАЧЕ 0

    КОНЕЦ

    )

Aгрегатная функция Тип результата Особенности
СУММА Число(15,3) Округляет до 3 знаков, если не указан другой формат
СРЗНАЧ Число(15,6) Точность увеличивается для уменьшения погрешности деления
МАКСИМУМ/МИНИМУМ Сохраняет тип исходных данных Если исходное поле строковое, результат тоже будет строкой
📊 Какой тип данных вы чаще всего преобразуете в числа в запросах?
Строки с разделителями
Булевы значения
Дата/Время
NULL/Неопределён
Другой

═══

4. Обработка NULL и неопределённых значений

Одна из самых коварных проблем при преобразовании типов — это обработка NULL (или Неопределено в терминах ). Если результат запроса содержит пустые значения, попытка привести их к числу приведёт к исключению. Решается это с помощью функции ЗНАЧЕНИЕ или конструкции ВЫБОР КОГДА.

Примеры безопасного преобразования:

ВЫБРАТЬ

ВЫРАЗИТЬ(ЗНАЧЕНИЕ(Сумма, 0),"Число(10,2)") КАК Сумма

ИЗ

Документ.ПоступлениеТоваров

Более гибкий вариант с условием:

ВЫБРАТЬ

ВЫБОР

КОГДА Сумма ЕСТЬ NULL

ТОГДА 0

ИНАЧЕ ВЫРАЗИТЬ(Сумма,"Число(10,2)")

КОНЕЦ КАК Сумма

ИЗ...

Если в данных могут встречаться строки, которые нельзя преобразовать в число (например, "Нет данных"), комбинируйте проверки:

ВЫБРАТЬ

ВЫБОР

КОГДА СуммаКакСтрока ="Нет данных" ИЛИ СуммаКакСтрока ЕСТЬ NULL

ТОГДА 0

КОГДА НЕ ПОПЫТКА ВЫРАЗИТЬ(СуммаКакСтрока,"Число") ТОГДА 0

ИНАЧЕ ВЫРАЗИТЬ(СуммаКакСтрока,"Число(10,2)")

КОНЕЦ КАК Сумма

⚠️ Внимание: Конструкция ПОПЫТКА в языке запросов работает только начиная с версии платформы 8.3.15. В более ранних релизах используйте ВЫБОР КОГДА с явной проверкой формата строки.

Исключить NULL с помощью ЗНАЧЕНИЕ|Проверить формат строки на наличие разделителей|Указать явную разрядность для финансовых данных|Обработать исключения через ВЫБОР КОГДА-->

═══

5. Оптимизация производительности при массовых преобразованиях

Преобразование типов в больших выборках может существенно замедлить выполнение запроса. Особенно это заметно при работе с виртуальными таблицами или динамическими списками, где данные извлекаются порциями. Вот ключевые рекомендации для оптимизации:

1. Переносите преобразования в код.

Если возможно, получайте данные в исходном виде, а преобразование выполняйте уже в модуле после выгрузки результата. Это снизит нагрузку на СУБД:

Результат = Запрос.Выполнить;

Выборка = Результат.Выбрать;

Пока Выборка.Следующий Цикл

ЧисловоеЗначение = Число(Выборка.СтрокаСуммы); // Преобразование в коде

КонецЦикла;

2. Используйте материализованные представления.

Если один и тот же запрос с преобразованиями выполняется часто, создайте материализованное представление (в PostgreSQL) или временную таблицу с уже преобразованными данными.

3. Избегайте вложенных функций.

Запрос вида:

ВЫБРАТЬ ВЫРАЗИТЬ(ЗАМЕНИТЬ(ЗАМЕНИТЬ(Строка,"",""),",","."),"Число")

будет выполняться дольше, чем:

ВЫБРАТЬ ВЫРАЗИТЬ(НормализованнаяСтрока,"Число")

ИЗ (ВЫБРАТЬ ЗАМЕНИТЬ(ЗАМЕНИТЬ(Строка,"",""),",",".") КАК НормализованнаяСтрока ИЗ...) КАК Подзапрос

Метод Производительность Когда использовать
Преобразование в запросе ⚠️ Низкая (нагрузка на СУБД) Малые выборки (< 1000 строк)
Преобразование в коде ✅ Высокая Большие выборки, сложные преобразования
Временные таблицы ✅✅ Очень высокая Часто повторяющиеся запросы
💡

Для выборок более 10 000 строк преобразование типов в коде после выполнения запроса ускоряет работу в 3-5 раз по сравнению с преобразованием в SQL-коде запроса.

═══

6. Типичные ошибки и их решения

Даже опытные разработчики сталкиваются с неочевидными ошибками при преобразовании типов. Рассмотрим самые распространённые случаи и способы их исправления.

Ошибка 1: Потеря точности при использовании КАК ЧИСЛО без указания разрядности.

Если в базе хранятся числа с 4 знаками после запятой (например, 123.4567), а вы используете КАК ЧИСЛО без параметров, результат будет округлён до 123.457. Решение:

ВЫРАЗИТЬ(Сумма,"Число(15,4)")

Ошибка 2: Преобразование даты в число.

Если попытаться привести дату к числу напрямую, получится количество дней с 1 января 0001 года. Чтобы получить год, месяц или день, используйте функции даты:

ВЫБРАТЬ

ГОД(ДатаДокумента) КАК Год,

МЕСЯЦ(ДатаДокумента) КАК Месяц,

ДЕНЬ(ДатаДокумента) КАК День

Ошибка 3: Неучтённые локальные настройки.

Если сервер и клиент работают с разными локалями, строковые числа могут интерпретироваться неверно. Например, строка "1,234" будет воспринята как 1.234 в английской локали и как 1234 — в русской. Решение:

  • 🔧 Явно нормализуйте строки перед преобразованием (см. раздел 2).
  • 🔧 Используйте УстановитьЛокаль в коде перед обработкой данных.
⚠️ Внимание: Настройки локали могут отличаться в разных сеансах (например, в фоновых заданиях и интерактивных сессиях). Всегда проверяйте текущую локаль с помощью ТекущаяЛокаль.

В языке запросов нет прямого доступа к настройкам локали, но вы можете передать её как параметр:

Запрос.УстановитьПараметр("Локаль", ТекущаяЛокаль);

ТекстЗапроса ="ВЫБРАТЬ ВЫБОР КОГДА &Локаль =""ru_RU"" ТОГДА...";

Или использовать глобальную переменную в модуле.

═══

7. Практический пример: сложный запрос с множественными преобразованиями

Рассмотрим реальный пример, где требуется:

  1. Получить данные из документа РеализацияТоваровУслуг.
  2. Преобразовать строковые суммы в числа с учётом разделителей.
  3. Обработать NULL в поле Скидка.
  4. Вычислить итоговую сумму с учётом НДС.

Исходные данные:

  • 📄 Поле СуммаДокумента — строка вида "1 234,56".
  • 📄 Поле Скидка — может быть NULL или числом.
  • 📄 Поле СтавкаНДС — строка ("20%", "10%", "Без НДС").

Решение:

ВЫБРАТЬ

ВЫРАЗИТЬ(

ЗАМЕНИТЬ(

ЗАМЕНИТЬ(

РеализацияТоваровУслуг.СуммаДокумента,

"",

""

),

",",

"."

),

"Число(15,2)"

) КАК СуммаБезСкидки,

ВЫРАЗИТЬ(

ЗНАЧЕНИЕ(

ВЫБОР

КОГДА РеализацияТоваровУслуг.Скидка ЕСТЬ NULL

ТОГДА 0

ИНАЧЕ РеализацияТоваровУслуг.Скидка

КОНЕЦ,

0

),

"Число(5,2)"

) КАК Скидка,

ВЫБОР

КОГДА РеализацияТоваровУслуг.СтавкаНДС ="Без НДС"

ТОГДА 0

КОГДА РеализацияТоваровУслуг.СтавкаНДС ="10%"

ТОГДА 10

КОГДА РеализацияТоваровУслуг.СтавкаНДС ="20%"

ТОГДА 20

ИНАЧЕ 0

КОНЕЦ КАК СтавкаНДСЧисло,

// Итоговая сумма с учётом скидки и НДС

ВЫРАЗИТЬ(

ЗАМЕНИТЬ(

ЗАМЕНИТЬ(

РеализацияТоваровУслуг.СуммаДокумента,

"",

""

),

",",

"."

),

"Число(15,2)"

) * (1 - ВЫРАЗИТЬ(ЗНАЧЕНИЕ(РеализацияТоваровУслуг.Скидка, 0),"Число(5,2)") / 100)

* (1 + ВЫБОР

КОГДА РеализацияТоваровУслуг.СтавкаНДС ="Без НДС" ТОГДА 0

КОГДА РеализацияТоваровУслуг.СтавкаНДС ="10%" ТОГДА 0.1

КОГДА РеализацияТоваровУслуг.СтавкаНДС ="20%" ТОГДА 0.2

ИНАЧЕ 0

КОНЕЦ) КАК СуммаИтоговая

ИЗ

Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

Критическая деталь: В этом примере сначала нормализуется строка суммы, затем применяется скидка, и только потом рассчитывается НДС. Порядок операций важен для корректного округления!

═══

FAQ: Частые вопросы по преобразованию типов в запросах 1С

Можно ли преобразовать булево значение в число прямо в запросе?

Да, булевы значения автоматически преобразуются в 1 (Истина) и 0 (Ложь) при использовании функций ВЫРАЗИТЬ или КАК ЧИСЛО. Например:

ВЫБРАТЬ ВЫРАЗИТЬ(Оплачено,"Число") КАК ОплаченоЧислом

Однако лучше явно указывать такое преобразование, чтобы код был понятнее.

Почему функция Число не работает в языке запросов?

Функция Число — это глобальная функция , доступная только в встроенном языке (в модулях). В языке запросов используйте ВЫРАЗИТЬ или КАК ЧИСЛО.

Как преобразовать результат запроса в число, если он возвращает массив?

Если запрос возвращает массив (например, при использовании ВЫБРАТЬ РАЗЛИЧНЫЕ с одной колонкой), преобразуйте его в число в коде:

МассивРезультатов = Запрос.Выполнить.Выгрузить;

ЧисловоеЗначение = Число(МассивРезультатов[0][0]);

Убедитесь, что массив не пустой, чтобы избежать ошибки.

Можно ли в одном запросе преобразовать несколько полей в числа с разной разрядностью?

Да, например:

ВЫБРАТЬ

ВЫРАЗИТЬ(Цена,"Число(10,2)") КАК Цена,

ВЫРАЗИТЬ(Количество,"Число(5,0)") КАК Количество,

ВЫРАЗИТЬ(Вес,"Число(8,3)") КАК Вес

ИЗ...

Это не влияет на производительность, так как преобразования выполняются параллельно.

Что делать, если после преобразования числа отображаются с лишними нулями (например, 100.000)?

Это связано с разрядностью типа. Используйте функцию ФОРМАТ в коде для форматирования вывода:

Сообщить(Формат(ЧисловоеЗначение,"ЧДЦ=2; ЧРД="""""));

Или настройте формат отображения в отчёте/форме.