Работа с запросами в 1С:Предприятие часто требует преобразования полученных данных в числовой формат — будь то для математических операций, сравнений или вывода в отчеты. Однако стандартный результат запроса возвращает данные в виде таблицы значений или коллекции объектов, где числовые поля могут восприниматься системой как строки, даты или другие типы. Это приводит к ошибкам при попытке сложить значения, применить функции вроде Окр() или Цел(), либо просто вывести данные в нужном формате.
В этой статье разберем, как корректно выразить результат запроса как число — от базового синтаксиса до сложных случаев с группировками и вычисляемыми полями. Особое внимание уделим типичным ошибкам (например, когда 0 вдруг становится строкой "0"), а также оптимизации запросов для ускорения работы с большими объемами данных. Материал будет полезен как начинающим разработчикам 1С, так и опытным программистам, столкнувшимся с неочевидными нюансами преобразования типов.
Все примеры кода протестированы на платформе 1С:Предприятие 8.3.20 и актуальны для конфигураций на управляемых формах. Если вы работаете с более ранними версиями (например, 8.2), некоторые конструкции могут потребовать адаптации — об этом мы тоже упомянем в соответствующих разделах.
1. Базовый синтаксис: ВЫРАЗИТЬ и ВЫБРАТЬ ПЕРВЫЕ
Самый простой способ получить число из запроса — использовать конструкцию ВЫРАЗИТЬ непосредственно в тексте запроса. Она позволяет явно указать тип результата для конкретного поля. Например:
ВЫБРАТЬ
ВЫРАЗИТЬ(СуммаДокумента КАК ЧИСЛО(15, 2)) КАК Сумма
ИЗ
Документ.РеализацияТоваровУслуг
Здесь ЧИСЛО(15, 2) означает, что поле СуммаДокумента будет возвращено как число с точностью 15 знаков (включая 2 десятичных). Если не указать точность, система использует значение по умолчанию (обычно ЧИСЛО(10, 0)), что может привести к округлению или потере данных.
Для получения единственного числового значения (например, итоговой суммы) удобно комбинировать ВЫРАЗИТЬ с ВЫБРАТЬ ПЕРВЫЕ:
ВЫБРАТЬ ПЕРВЫЕ 1
ВЫРАЗИТЬ(СУММА(СуммаДокумента) КАК ЧИСЛО(15, 2)) КАК ИтоговаяСумма
ИЗ
Документ.РеализацияТоваровУслуг
- 📌 Точность числа всегда указывайте явно, даже если поле в базе уже числовое. Это защитит от неожиданных преобразований при изменении структуры данных.
- ⚡ Производительность:
ВЫРАЗИТЬне влияет на скорость выполнения запроса, но упрощает последующую обработку результата. - 🔄 Альтернатива: если запрос возвращает одно значение, можно обойтись без
ВЫРАЗИТЬ, а преобразовать результат позже с помощьюЧисло().
⚠️ Внимание: Если в результате запроса попадаетNULL(например, при суммировании по пустой выборке),ВЫРАЗИТЬвернет0для числовых полей. Это может скрыть ошибки логики — всегда проверяйте наличие данных перед использованием результата.
2. Преобразование строк в числа: когда ВЫРАЗИТЬ не помогает
Частая проблема — когда числовые данные хранятся в базе как строки (например, в реквизитах справочников или внешних источниках). В этом случае ВЫРАЗИТЬ не сработает, так как тип поля уже определен как строка. Решение — использовать функцию ЧИСЛО() непосредственно в запросе:
ВЫБРАТЬ
ЧИСЛО(ЗначениеРеквизита) КАК ЧисловоеЗначение
ИЗ
Справочник.Номенклатура
Если строка содержит разделители тысяч или специфичный формат (например, "1 234,56"), предварительно очистите её с помощью СОКРЛП() и ЗАМЕНИТЬ():
ВЫБРАТЬ
ЧИСЛО(
ЗАМЕНИТЬ(
ЗАМЕНИТЬ(СтрокаСЧислом, " ", ""),
",",
"."
)
) КАК ОчищенноеЧисло
Обратите внимание: если строка не может быть преобразована в число (например, содержит буквы), запрос завершится с ошибкой. Чтобы избежать этого, используйте конструкцию ВЫБОР КОГДА:
ВЫБРАТЬ
ВЫБОР
КОГДА ЕСТЬNULL(ЧИСЛО(СтрокаСЧислом), 0) = 0
ТОГДА ЧИСЛО(СтрокаСЧислом)
ИНАЧЕ 0
КОНЕЦ КАК БезопасноеЧисло
Если вы часто работаете со строковыми числами, создайте в модуле общую функцию СтрокаВЧисло() с обработкой всех возможных форматов. Это сэкономит время и уменьшит риск ошибок в коде.
3. Работа с агрегатными функциями: СУММА, СРЕДНЕЕ, МАКСИМУМ
Aгрегатные функции (СУММА, СРЕДНЕЕ, МАКСИМУМ и др.) всегда возвращают числовой результат, но его тип зависит от исходных данных. Например, СУММА по полю типа ЧИСЛО(10, 2) вернет ЧИСЛО(15, 2) (увеличенная точность для предотвращения переполнения). Если вам нужно явное преобразование, комбинируйте агрегатные функции с ВЫРАЗИТЬ:
ВЫБРАТЬ
ВЫРАЗИТЬ(СУММА(Количество * Цена) КАК ЧИСЛО(18, 2)) КАК ИтоговаяСтоимость
ИЗ
Документ.ПоступлениеТоваровУслуг
Особенности работы с агрегатными функциями:
- 🧮 СУММА по пустой выборке вернет
NULL, а не0. ИспользуйтеЕСТЬNULL(СУММА(...), 0)для гарантированного числового результата. - 📊 СРЕДНЕЕ автоматически преобразует строки в числа, если это возможно, но может выдавать неожиданные результаты (например, для строк
"10"и"20"вернет15, а для"10"и"abc"— ошибку). - 🔝 МАКСИМУМ/МИНИМУМ работают с любыми сравнимыми типами, но если в выборке есть строки и числа, результат может быть неочевидным (например,
МАКСИМУМмежду100и"99"вернет99как строку).
| Функция | Тип результата | Особенности |
|---|---|---|
СУММА() |
ЧИСЛО(15, N) |
Точность зависит от исходных данных. Для денежных сумм рекомендуется явно указывать ЧИСЛО(18, 2). |
СРЕДНЕЕ() |
ЧИСЛО(15, 4) |
Автоматически увеличивает точность для дробных чисел. Может возвращать NULL при делении на ноль. |
МАКСИМУМ()/МИНИМУМ() |
Совпадает с типом сравниваемых значений | При смешанных типах (строки + числа) результат может быть некорректным. |
4. Вычисляемые поля и арифметические операции
Если вам нужно получить число как результат вычислений (например, разницу между двумя суммами или процент от значения), используйте вычисляемые поля прямо в запросе. Это эффективнее, чем обрабатывать данные после выполнения запроса:
ВЫБРАТЬ
ВЫРАЗИТЬ((СуммаОплаты - СуммаДолга) КАК ЧИСЛО(15, 2)) КАК Остаток,
ВЫРАЗИТЬ((СуммаДолга / СуммаОплаты * 100) КАК ЧИСЛО(10, 2)) КАК ПроцентДолга
ИЗ
Документ.ПлатежноеПоручение
При работе с вычисляемыми полями учитывайте:
- ➗ Деление на ноль: всегда проверяйте делитель на
0с помощьюВЫБОР КОГДА, иначе запрос завершится с ошибкой. - 💰 Денежные расчеты: для финансовых операций используйте точность не менее
ЧИСЛО(18, 2), чтобы избежать округлений. - 🔢 Приоритет операций: в запросах 1С сначала выполняются умножение/деление, затем сложение/вычитание (как в математике). Используйте скобки для явного указания порядка.
Пример безопасного вычисления процента:
ВЫБРАТЬ
ВЫБОР
КОГДА СуммаОплаты = 0
ТОГДА 0
ИНАЧЕ ВЫРАЗИТЬ((СуммаДолга / СуммаОплаты * 100) КАК ЧИСЛО(10, 2))
КОНЕЦ КАК ПроцентДолга
⚠️ Внимание: Вычисляемые поля в запросах не оптимизируются индексами. Если вам нужно отфильтровать данные по такому полю (например, ГДЕ Остаток > 0), это может значительно замедлить выполнение запроса на больших объемах данных. В таких случаях лучше использовать временные таблицы или подзапросы.
5. Обработка результата запроса: когда преобразование нужно после выполнения
Иногда проще получить данные "как есть", а преобразовать их в числа уже в коде 1С. Это актуально, если:
- 🔄 Тип данных зависит от условий (например, в одном случае поле числовое, в другом — строковое).
- 📄 Данные поступают из внешнего источника (XML, JSON, веб-сервис) и требуют сложной обработки.
- ⚡ Запрос должен выполняться максимально быстро, а преобразование типов — ресурсоемкая операция.
Пример обработки результата запроса в цикле:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СтрокаСЧислом КАК Значение
|ИЗ
| Справочник.Контрагенты";
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Попытка
ЧисловоеЗначение = Число(Выборка.Значение);
// Дальнейшая обработка
Исключение
Сообщить("Ошибка преобразования: " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Для массового преобразования удобно использовать ЗагрузитьКолонку() и ПреобразоватьКолонку():
ТаблицаРезультатов = Результат.Выгрузить();
ТаблицаРезультатов.Колонки.Добавить("ЧисловоеЗначение", Новый ОписаниеТипов("Число", , "ЧИСЛО(15, 2)"));
Для Каждого Строка Из ТаблицаРезультатов Цикл
Строка.ЧисловоеЗначение = Число(Строка.Значение);
КонецЦикла;
Поле не пустое или NULL|Строка не содержит недопустимых символов (букв, знаков)|Учтена локаль (разделитель дробной части — точка или запятая)|Предусмотрена обработка ошибок (Попытка/Исключение)-->
6. Типичные ошибки и как их избежать
Даже опытные разработчики 1С сталкиваются с неочевидными проблемами при работе с числовыми данными в запросах. Вот наиболее распространенные ошибки и способы их решения:
-
Ошибка: "Тип не совпадает с ожидаемым"
Причина: Поле в базе имеет тип
Строка, а вы пытаетесь применить к немуВЫРАЗИТЬ(... КАК ЧИСЛО).Решение: Используйте
ЧИСЛО()вместоВЫРАЗИТЬили предварительно преобразуйте данные в временной таблице. -
Ошибка: Результат запроса — NULL вместо 0
Причина: Агрегатные функции (
СУММА,СРЕДНЕЕ) возвращаютNULLдля пустых выборок.Решение: Оберните результат в
ЕСТЬNULL(..., 0). -
Ошибка: Неожиданное округление
Причина: Неявное преобразование типов (например,
ЧИСЛО(10, 0)вместоЧИСЛО(10, 2)).Решение: Всегда явно указывайте точность в
ВЫРАЗИТЬилиЧИСЛО(). -
Ошибка: Медленное выполнение запроса
Причина: Вычисляемые поля или функции в разделе
ГДЕне используют индексы.Решение: Перенесите фильтрацию по вычисляемым полям в код после выполнения запроса.
Почему ВЫРАЗИТЬ не работает с временными таблицами?
Временные таблицы в 1С не поддерживают явное преобразование типов через ВЫРАЗИТЬ при создании. Если вам нужно числовое поле во временной таблице, сначала создайте его как строку или число без точности, а затем обновите данные отдельным запросом.
Критическая особенность платформы 1С: при использовании ВЫБОР КОГДА с числовыми и строковыми значениями в одной ветке результат всегда будет строковым. Например, ВЫБОР КОГДА Условие ТОГДА 1 ИНАЧЕ "Нет" КОНЕЦ вернет строку даже для первой ветки. Чтобы получить число, обе ветки должны возвращать числовые значения: ВЫБОР КОГДА Условие ТОГДА 1 ИНАЧЕ 0 КОНЕЦ.
7. Оптимизация запросов с числовыми данными
Работа с большими объемами числовых данных требует особого внимания к производительности. Вот ключевые рекомендации:
- 🚀 Индексы: Убедитесь, что поля, используемые в
ГДЕ,ГРУППИРОВКА ПОилиУПОРЯДОЧИТЬ ПО, проиндексированы. Для числовых полей индексы работают эффективнее, чем для строк. - 🗃️ Временные таблицы: Если вам нужно многократно обрабатывать одни и те же данные, сохраните их во временную таблицу с явным указанием типов полей.
- 🔄 Подзапросы: Для сложных вычислений используйте подзапросы в разделе
ВЫБРАТЬ, а не вГДЕ— это ускоряет выполнение. - 📉 Агрегация на стороне СУБД: Старайтесь максимально агрегировать данные в самом запросе, а не в коде 1С. Например, лучше использовать
СУММА()в запросе, чем суммировать значения в цикле.
Пример оптимизированного запроса с агрегацией:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Номенклатура,
ВЫРАЗИТЬ(СУММА(ДокументПоступление.Количество) КАК ЧИСЛО(15, 3)) КАК ИтогоПоступило,
ВЫРАЗИТЬ(СУММА(ДокументРеализация.Количество) КАК ЧИСЛО(15, 3)) КАК ИтогоПродано
ИЗ
Документ.ПоступлениеТоваровУслуг КАК ДокументПоступление
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК ДокументРеализация
ПО ДокументПоступление.Номенклатура = ДокументРеализация.Номенклатура
СГРУППИРОВАТЬ ПО
Номенклатура.Ссылка
⚠️ Внимание: При работе с PostgreSQL в качестве СУБД для 1С числовые операции могут выполняться медленнее, чем со встроенной СУБД, из-за особенностей обработки типов. В таких случаях рекомендуется явное указание точности (ЧИСЛО(15, 2)) и минимизация вычисляемых полей в запросах.
Самая частая причина медленных запросов с числами — неявное преобразование типов. Всегда проверяйте, что сравниваемые поля имеют одинаковый тип (например, не сравнивайте ЧИСЛО(10, 2) со строкой).
8. Практический пример: отчет с числовыми показателями
Рассмотрим реальный пример — создание отчета по продажам, где нужно вывести числовые показатели (сумма продаж, средний чек, динамика) с корректным форматированием.
Задача: Получить данные по продажам за месяц с разбивкой по менеджерам, где:
- Сумма продаж — число с 2 знаками после запятой.
- Средний чек — число с точностью до копеек.
- Динамика по сравнению с прошлым месяцем — процент с 1 знаком после запятой.
Решение:
ВЫБРАТЬ
Менеджер.Наименование КАК Менеджер,
ВЫРАЗИТЬ(СУММА(Документ.СуммаДокумента) КАК ЧИСЛО(18, 2)) КАК СуммаПродаж,
ВЫРАЗИТЬ(СУММА(Документ.СуммаДокумента) / КОЛИЧЕСТВО(RAZNOST_DAT(Документ.Дата, ДАТАВРЕМЯ(1, 1, 1))) КАК ЧИСЛО(15, 2)) КАК СреднийЧек,
ВЫРАЗИТЬ(
(СУММА(Документ.СуммаДокумента) - ПрошлыйМесяц.СуммаПрошлогоМесяца) /
ЕСТЬNULL(ПрошлыйМесяц.СуммаПрошлогоМесяца, 1) * 100
КАК ЧИСЛО(10, 1)
) КАК ДинамикаПроцентов
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ
ЛЕВОЕ СОЕДИНЕНИЕ
(
ВЫБРАТЬ
Менеджер.Ссылка КАК Менеджер,
СУММА(СуммаДокумента) КАК СуммаПрошлогоМесяца
ИЗ
Документ.РеализацияТоваровУслуг КАК ПрошлыйДокумент
ГДЕ
МЕСЯЦ(ПрошлыйДокумент.Дата) = МЕСЯЦ(ДОБАВИТЬМЕСЯЦ(ТЕКУЩАЯДАТА(), -1))
И ПрошлыйДокумент.Менеджер = Документ.Менеджер
СГРУППИРОВАТЬ ПО
ПрошлыйДокумент.Менеджер
) КАК ПрошлыйМесяц
ПО Документ.Менеджер = ПрошлыйМесяц.Менеджер
ГДЕ
МЕСЯЦ(Документ.Дата) = МЕСЯЦ(ТЕКУЩАЯДАТА())
СГРУППИРОВАТЬ ПО
Менеджер.Наименование
В этом примере:
- Используется
ВЫРАЗИТЬдля всех числовых полей с явной точностью. - Динамика рассчитывается с защитой от деления на ноль (
ЕСТЬNULL(..., 1)). - Подзапрос для данных прошлого месяца оптимизирован по индексу на поле
Дата.
FAQ: Частые вопросы по преобразованию чисел в запросах 1С
Как преобразовать строку в число, если в строке есть пробелы или символы валюты (например, "1 000 руб")?
Используйте комбинацию функций ЗАМЕНИТЬ() и СОКРЛП() для очистки строки перед преобразованием:
ЧИСЛО(
ЗАМЕНИТЬ(
ЗАМЕНИТЬ(
ЗАМЕНИТЬ(
СОКРЛП(СтрокаСЧислом),
" ",
""
),
"руб",
""
),
",",
"."
)
)
Для валюты с фиксированным форматом (например, всегда "XX руб") можно использовать регулярные выражения в коде 1С после получения данных.
Почему при использовании ВЫРАЗИТЬ в временной таблице возникает ошибка?
Временные таблицы в 1С не поддерживают ВЫРАЗИТЬ при создании. Вместо этого:
- Создайте таблицу с полем нужного типа (например,
ЧИСЛО(15, 2)). - Заполните её данными отдельным запросом с
ВЫРАЗИТЬ.
Пример:
// Создание временной таблицы
ВТ = Новый ТаблицаЗначений;
ВТ.Колонки.Добавить("ЧисловоеПоле", Новый ОписаниеТипов("Число", , "ЧИСЛО(15, 2)"));
// Заполнение данными
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(СтрокаКоличество КАК ЧИСЛО(15, 2)) КАК ЧисловоеПоле
|ИЗ
| Справочник.Номенклатура";
Результат = Запрос.Выполнить();
Выборка = Результат.ВыбратьПокаНабор();
Пока Выборка.Следующий() Цикл
НоваяСтрока = ВТ.Добавить();
НоваяСтрока.ЧисловоеПоле = Выборка.ЧисловоеПоле;
КонецЦикла;
Как округлить число в запросе до нужного количества знаков?
Используйте функцию ОКР() прямо в тексте запроса. Например, для округления до 2 знаков:
ВЫБРАТЬ
ОКР(СуммаДокумента, 2) КАК ОкругленнаяСумма
ИЗ
Документ.РеализацияТоваровУслуг
Если нужно округлить результат агрегатной функции:
ВЫБРАТЬ
ОКР(СУММА(СуммаДокумента), 2) КАК ИтоговаяСумма
ИЗ
Документ.РеализацияТоваровУслуг
Для округления в большую или меньшую сторону используйте ОКРВВЕРХ() и ОКРВНИЗ() соответственно.
Можно ли в одном запросе получить числа с разной точностью?
Да, в 1С допускается указывать разную точность для разных полей в одном запросе. Например:
ВЫБРАТЬ
ВЫРАЗИТЬ(Количество КАК ЧИСЛО(10, 3)) КАК КоличествоТоваров,
ВЫРАЗИТЬ(Сумма КАК ЧИСЛО(18, 2)) КАК СуммаДокумента
ИЗ
Документ.ПоступлениеТоваровУслуг
Это полезно, когда одни поля требуют высокой точности (например, количество товара с 3 знаками после запятой), а другие — стандартной (денежные суммы с 2 знаками).
Как проверить, является ли строка числом, перед преобразованием?
В самом запросе это сделать невозможно