Работа с запросами в 1С:Предприятие 8.3 часто требует преобразования полученных данных в числовой формат — будь то для расчётов, сравнений или вывода в отчёты. Однако не всегда результат запроса сразу имеет тип Число. Строки из полей справочников, даты, булевы значения или даже NULL могут стать причиной ошибок, если их не привести к нужному типу. Эта статья охватывает все актуальные способы преобразования, включая нюансы работы с агрегатными функциями, параметрами и динамическими списками.
Особое внимание уделено типичным ошибкам, которые возникают при некорректном приведении типов — от падения производительности до исключений вида "Ошибка приведения значения к типу Число". Вы узнаете, как избежать потери точности при работе с дробными числами, почему функция ВЫРАЗИТЬ иногда возвращает неожиданные результаты, и как правильно обрабатывать пустые значения. Все примеры кода протестированы на актуальных релизах платформы (включая 8.3.23).
Если вы только начинаете работать с запросами в 1С, начните с раздела о базовых функциях. Опытным разработчикам будет полезен раздел про оптимизацию преобразований в больших выборках и сравнение производительности разных методов.
═══
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грегатные функции в запросах 1С (СУММА, СРЗНАЧ, МАКСИМУМ и т.д.) всегда возвращают результат типа Число, даже если исходные данные были строковыми или булевыми. Однако это не означает, что преобразование происходит автоматически корректно.
Типичные ошибки:
- 📉 Потеря точности: Если в выборке есть строки вида
"1000.123456789", а вы используетеСУММАбез явного указания разрядности, результат будет округлён до 3 знаков после запятой (по умолчанию). - 🚫 Исключения: Если среди данных попадётся строка, которую невозможно преобразовать в число (например,
"Н/Д"), запрос завершится с ошибкой.
Рекомендации по работе с агрегатными функциями:
- Всегда явно указывайте разрядность для финансовых данных:
СУММА(ВЫРАЗИТЬ(СуммаДокумента,"Число(15,2)")) - Используйте
ВЫБОР КОГДАдля фильтрации некорректных значений:СУММА(ВЫБОР
КОГДА НЕ СуммаКакСтрока ПОДОБНО"%[^0-9.,-]%"
ТОГДА ВЫРАЗИТЬ(СуммаКакСтрока,"Число")
ИНАЧЕ 0
КОНЕЦ
)
| Aгрегатная функция | Тип результата | Особенности |
|---|---|---|
СУММА |
Число(15,3) |
Округляет до 3 знаков, если не указан другой формат |
СРЗНАЧ |
Число(15,6) |
Точность увеличивается для уменьшения погрешности деления |
МАКСИМУМ/МИНИМУМ |
Сохраняет тип исходных данных | Если исходное поле строковое, результат тоже будет строкой |
═══
4. Обработка NULL и неопределённых значений
Одна из самых коварных проблем при преобразовании типов — это обработка NULL (или Неопределено в терминах 1С). Если результат запроса содержит пустые значения, попытка привести их к числу приведёт к исключению. Решается это с помощью функции ЗНАЧЕНИЕ или конструкции ВЫБОР КОГДА.
Примеры безопасного преобразования:
ВЫБРАТЬ
ВЫРАЗИТЬ(ЗНАЧЕНИЕ(Сумма, 0),"Число(10,2)") КАК Сумма
ИЗ
Документ.ПоступлениеТоваров
Более гибкий вариант с условием:
ВЫБРАТЬ
ВЫБОР
КОГДА Сумма ЕСТЬ NULL
ТОГДА 0
ИНАЧЕ ВЫРАЗИТЬ(Сумма,"Число(10,2)")
КОНЕЦ КАК Сумма
ИЗ...
Если в данных могут встречаться строки, которые нельзя преобразовать в число (например, "Нет данных"), комбинируйте проверки:
ВЫБРАТЬ
ВЫБОР
КОГДА СуммаКакСтрока ="Нет данных" ИЛИ СуммаКакСтрока ЕСТЬ NULL
ТОГДА 0
КОГДА НЕ ПОПЫТКА ВЫРАЗИТЬ(СуммаКакСтрока,"Число") ТОГДА 0
ИНАЧЕ ВЫРАЗИТЬ(СуммаКакСтрока,"Число(10,2)")
КОНЕЦ КАК Сумма
⚠️ Внимание: КонструкцияПОПЫТКАв языке запросов 1С работает только начиная с версии платформы 8.3.15. В более ранних релизах используйтеВЫБОР КОГДАс явной проверкой формата строки.
Исключить NULL с помощью ЗНАЧЕНИЕ|Проверить формат строки на наличие разделителей|Указать явную разрядность для финансовых данных|Обработать исключения через ВЫБОР КОГДА-->
═══
5. Оптимизация производительности при массовых преобразованиях
Преобразование типов в больших выборках может существенно замедлить выполнение запроса. Особенно это заметно при работе с виртуальными таблицами или динамическими списками, где данные извлекаются порциями. Вот ключевые рекомендации для оптимизации:
1. Переносите преобразования в код.
Если возможно, получайте данные в исходном виде, а преобразование выполняйте уже в модуле 1С после выгрузки результата. Это снизит нагрузку на СУБД:
Результат = Запрос.Выполнить;
Выборка = Результат.Выбрать;
Пока Выборка.Следующий Цикл
ЧисловоеЗначение = Число(Выборка.СтрокаСуммы); // Преобразование в коде
КонецЦикла;
2. Используйте материализованные представления.
Если один и тот же запрос с преобразованиями выполняется часто, создайте материализованное представление (в PostgreSQL) или временную таблицу с уже преобразованными данными.
3. Избегайте вложенных функций.
Запрос вида:
ВЫБРАТЬ ВЫРАЗИТЬ(ЗАМЕНИТЬ(ЗАМЕНИТЬ(Строка,"",""),",","."),"Число")
будет выполняться дольше, чем:
ВЫБРАТЬ ВЫРАЗИТЬ(НормализованнаяСтрока,"Число")
ИЗ (ВЫБРАТЬ ЗАМЕНИТЬ(ЗАМЕНИТЬ(Строка,"",""),",",".") КАК НормализованнаяСтрока ИЗ...) КАК Подзапрос
| Метод | Производительность | Когда использовать |
|---|---|---|
| Преобразование в запросе | ⚠️ Низкая (нагрузка на СУБД) | Малые выборки (< 1000 строк) |
| Преобразование в коде | ✅ Высокая | Большие выборки, сложные преобразования |
| Временные таблицы | ✅✅ Очень высокая | Часто повторяющиеся запросы |
Для выборок более 10 000 строк преобразование типов в коде после выполнения запроса ускоряет работу в 3-5 раз по сравнению с преобразованием в SQL-коде запроса.
═══
6. Типичные ошибки и их решения
Даже опытные разработчики 1С сталкиваются с неочевидными ошибками при преобразовании типов. Рассмотрим самые распространённые случаи и способы их исправления.
Ошибка 1: Потеря точности при использовании КАК ЧИСЛО без указания разрядности.
Если в базе хранятся числа с 4 знаками после запятой (например, 123.4567), а вы используете КАК ЧИСЛО без параметров, результат будет округлён до 123.457. Решение:
ВЫРАЗИТЬ(Сумма,"Число(15,4)")
Ошибка 2: Преобразование даты в число.
Если попытаться привести дату к числу напрямую, получится количество дней с 1 января 0001 года. Чтобы получить год, месяц или день, используйте функции даты:
ВЫБРАТЬ
ГОД(ДатаДокумента) КАК Год,
МЕСЯЦ(ДатаДокумента) КАК Месяц,
ДЕНЬ(ДатаДокумента) КАК День
Ошибка 3: Неучтённые локальные настройки.
Если сервер и клиент 1С работают с разными локалями, строковые числа могут интерпретироваться неверно. Например, строка "1,234" будет воспринята как 1.234 в английской локали и как 1234 — в русской. Решение:
- 🔧 Явно нормализуйте строки перед преобразованием (см. раздел 2).
- 🔧 Используйте
УстановитьЛокальв коде перед обработкой данных.
⚠️ Внимание: Настройки локали могут отличаться в разных сеансах 1С (например, в фоновых заданиях и интерактивных сессиях). Всегда проверяйте текущую локаль с помощью ТекущаяЛокаль.
В языке запросов нет прямого доступа к настройкам локали, но вы можете передать её как параметр:
Запрос.УстановитьПараметр("Локаль", ТекущаяЛокаль);
ТекстЗапроса ="ВЫБРАТЬ ВЫБОР КОГДА &Локаль =""ru_RU"" ТОГДА...";
Или использовать глобальную переменную в модуле.
═══
7. Практический пример: сложный запрос с множественными преобразованиями
Рассмотрим реальный пример, где требуется:
- Получить данные из документа
РеализацияТоваровУслуг. - Преобразовать строковые суммы в числа с учётом разделителей.
- Обработать
NULLв полеСкидка. - Вычислить итоговую сумму с учётом НДС.
Исходные данные:
- 📄 Поле
СуммаДокумента— строка вида"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 (Ложь) при использовании функций ВЫРАЗИТЬ или КАК ЧИСЛО. Например:
ВЫБРАТЬ ВЫРАЗИТЬ(Оплачено,"Число") КАК ОплаченоЧислом
Однако лучше явно указывать такое преобразование, чтобы код был понятнее.
Почему функция Число не работает в языке запросов?
Функция Число — это глобальная функция 1С, доступная только в встроенном языке (в модулях). В языке запросов используйте ВЫРАЗИТЬ или КАК ЧИСЛО.
Как преобразовать результат запроса в число, если он возвращает массив?
Если запрос возвращает массив (например, при использовании ВЫБРАТЬ РАЗЛИЧНЫЕ с одной колонкой), преобразуйте его в число в коде:
МассивРезультатов = Запрос.Выполнить.Выгрузить;
ЧисловоеЗначение = Число(МассивРезультатов[0][0]);
Убедитесь, что массив не пустой, чтобы избежать ошибки.
Можно ли в одном запросе преобразовать несколько полей в числа с разной разрядностью?
Да, например:
ВЫБРАТЬ
ВЫРАЗИТЬ(Цена,"Число(10,2)") КАК Цена,
ВЫРАЗИТЬ(Количество,"Число(5,0)") КАК Количество,
ВЫРАЗИТЬ(Вес,"Число(8,3)") КАК Вес
ИЗ...
Это не влияет на производительность, так как преобразования выполняются параллельно.
Что делать, если после преобразования числа отображаются с лишними нулями (например, 100.000)?
Это связано с разрядностью типа. Используйте функцию ФОРМАТ в коде 1С для форматирования вывода:
Сообщить(Формат(ЧисловоеЗначение,"ЧДЦ=2; ЧРД="""""));
Или настройте формат отображения в отчёте/форме.