Работа со строковыми данными, которые фактически содержат числовые значения, — одна из самых распространённых задач при написании запросов в 1С:Предприятие. Например, в базе могут храниться артикулы, номера документов или коды контрагентов в текстовом формате, но для фильтрации или сортировки их нужно сравнивать как числа. Неправильное преобразование приводит к ошибкам, падению производительности или некорректным результатам.
В этой статье разберём все способы приведения строк к числовому типу прямо в запросе: от стандартных функций ВАЛ() и ЧИСЛО() до малоизвестных приёмов с ПРЕОБРАЗОВАТЬ() и ЗНАЧ(). Особое внимание уделим типовым ошибкам (например, неявное преобразование строки "123.45" в число 12345 при отсутствии точки как разделителя) и оптимизации запросов для крупных баз.
Почему строку нельзя сравнивать как число напрямую
В 1С:Предприятие 8 строковые и числовые типы данных обрабатываются по-разному даже в условиях ГДЕ. Если попытаться сравнить строку "100" с числом 100 без явного преобразования, система либо выдаст ошибку, либо выполнит неявное приведение — но не всегда так, как вы ожидаете.
Основные проблемы:
- 🔢 Лексикографическая сортировка: строка
"1000"в алфавитном порядке идёт после"200", хотя численно это неверно. - ❌ Ошибки сравнения: выражение
ГДЕ СтрокаПоле = 100приведёт к исключению, если поле имеет типСтрока. - ⚠️ Потеря точности: строка
"123,45"может быть интерпретирована как12345, если разделитель дробной части не учтён.
Пример некорректного запроса:
ВЫБРАТЬ
Номенклатура.Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Артикул > 1000 // Ошибка, если Артикул - строка!
⚠️ Внимание: В некоторых конфигурациях (например, 1С:УТ 11) артикулы хранятся как строки, даже если визуально выглядят как числа. Всегда проверяйте реальный тип поля в метаданных!
Способы преобразования строки в число в запросе
Существует несколько встроенных функций для явного приведения строк к числовому типу. Их выбор зависит от формата исходных данных и требуемой точности.
1. Функция ВАЛ()
Самый универсальный метод — ВАЛ(Строка). Она преобразует строку в число с учётом региональных настроек (разделитель дробной части, тысячных разрядов). Подходит для большинства случаев:
ВЫБРАТЬ
ВАЛ(Номенклатура.Артикул) КАК АртикулЧисло
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
ВАЛ(Номенклатура.Артикул) > 1000
Особенности ВАЛ():
- 📌 Преобразует пустую строку в
0. - 📌 Игнорирует пробелы в начале и конце строки.
- ❌ Выдаёт ошибку, если строка содержит недопустимые символы (например, буквы).
2. Функция ЧИСЛО()
ЧИСЛО(Строка) аналогична ВАЛ(), но строже относится к формату. Например, не проигнорирует пробелы:
ВЫБРАТЬ
ЧИСЛО(ЗАМЕНИТЬ(Номенклатура.Артикул, " ", "")) КАК АртикулЧисло
Когда использовать:
- 🔍 Если нужно гарантированно отсечь строки с "мусором" (например, артикулы вида
"A100"). - 🔢 Когда требуется высокая производительность —
ЧИСЛО()работает быстрееВАЛ()на больших выборках.
3. ПРЕОБРАЗОВАТЬ() и ЗНАЧ()
Для сложных случаев (например, когда строка содержит разделители тысяч) подходит конструкция:
ВЫБРАТЬ
ПРЕОБРАЗОВАТЬ(ЗНАЧ(Номенклатура.Артикул), "Число") КАК АртикулЧисло
Это комбинация приведения к типу 1С (ЗНАЧ()) и явного преобразования (ПРЕОБРАЗОВАТЬ()). Полезно, если строка приходит из внешнего источника с нестандартным форматом.
Типовые ошибки и как их избежать
Даже опытные разработчики сталкиваются с подводными камнями при работе со строковыми числами. Рассмотрим самые распространённые.
1. Неучёт региональных настроек
Если в строке дробная часть отделена запятой ("123,45"), а в системе установлен разделитель-точка, ВАЛ() вернёт 123 вместо 123.45. Решение:
ВЫБРАТЬ
ВАЛ(СТРЗАМЕНИТЬ(Номенклатура.ЦенаСтрокой, ",", ".")) КАК ЦенаЧисло
2. Пустые строки и NULL
ВАЛ(NULL) и ВАЛ("") возвращают 0, что может исказить результаты. Чтобы исключить такие записи:
ВЫБРАТЬ
ВАЛ(Номенклатура.Артикул) КАК АртикулЧисло
ГДЕ
НЕ Номенклатура.Артикул ЕСТЬ NULL
И НЕ Номенклатура.Артикул = ""
3. Переполнение числового типа
Если строка содержит число больше 2^31-1 (для типа Число(10,0)), произойдёт ошибка. Для больших значений используйте:
ВЫБРАЗТЬ
ПРЕОБРАЗОВАТЬ(ЗНАЧ(Номенклатура.Код), "Число(15,0)") КАК КодЧисло
⚠️ Внимание: В конфигурациях с включённым режимом совместимости 1С:Предприятие 7.7 функция ВАЛ() может вести себя иначе — всегда проверяйте поведение на тестовой базе!
Убедиться, что поле действительно содержит числовые символы|Проверить региональные настройки (разделители)|Исключить NULL и пустые строки|Оценить диапазон значений (не превышает лимиты типа)
-->
Оптимизация производительности
Преобразование строк в числа в запросе может значительно замедлить выполнение на больших таблицах. Рассмотрим способы оптимизации.
1. Предварительная обработка данных
Если возможно, преобразуйте строковые поля в числовые до выполнения запроса (например, при загрузке данных). Это ускорит фильтрацию и сортировку.
2. Использование индексов
Создайте вычисляемое поле с числовым значением и проиндексируйте его:
// В модуле объекта
Процедура ПриЗаписи()
Если НЕ ЗначениеЗаполнено(АртикулЧисло) Тогда
АртикулЧисло = ВАЛ(Артикул);
КонецЕсли;
КонецПроцедуры
Затем в запросе используйте уже числовое поле:
ВЫБРАТЬ
Номенклатура.Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.АртикулЧисло > 1000
3. Альтернативные подходы для фильтрации
Если преобразование в числе занимает много времени, используйте строковые функции для предварительной фильтрации:
ВЫБРАТЬ
Номенклатура.Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
НАЧИНАЕТСЯС(Номенклатура.Артикул, "1") // Отсекаем заведомо нечисловые строки
И ВАЛ(Номенклатура.Артикул) > 1000
| Метод преобразования | Производительность | Надёжность | Когда использовать |
|---|---|---|---|
ВАЛ() |
Средняя | Высокая | Универсальный случай |
ЧИСЛО() |
Высокая | Средняя | Чистые числовые строки |
ПРЕОБРАЗОВАТЬ(ЗНАЧ(), "Число") |
Низкая | Высокая | Сложные форматы |
| Предварительное вычисляемое поле | Максимальная | Максимальная | Критичные по скорости запросы |
Для ускорения запросов с преобразованием строк в числа используйте вычисляемые поля с индексами или предварительную фильтрацию по строковым шаблонам.
Работа с дробными числами
Особую сложность представляют строки, содержащие дробные числа (например, цены или веса). Здесь важно учитывать:
- 📏 Разделитель дробной части: запятая или точка.
- 🔢 Количество знаков после запятой.
- ⚠️ Локальные настройки пользователя, под которым выполняется запрос.
Пример обработки цены в формате "1 234,56":
ВЫБРАТЬ
ВАЛ(СТРЗАМЕНИТЬ(СТРЗАМЕНИТЬ(Документ.СуммаСтрокой, " ", ""), ",", ".")) КАК СуммаЧисло
Для гарантированно корректного преобразования используйте функцию Формат() с явным указанием формата:
ВЫБРАТЬ
ЧИСЛО(Формат(Документ.СуммаСтрокой, "ЧДЦ=.; ЧРД= ")) КАК СуммаЧисло
Если в базе хранятся строковые цены с разными разделителями, создайте обработку, которая приведёт их к единому формату при загрузке данных. Это избавит от проблем с преобразованием в будущем.
Примеры реальных запросов
Разберём практические случаи, где преобразование строк в числа необходимо.
1. Фильтрация номенклатуры по артикулу
Задача: выбрать товары с артикулами в диапазоне 1000–2000 (артикулы хранятся как строки).
ВЫБРАТЬ
Номенклатура.Наименование,
Номенклатура.Артикул
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
ВАЛ(Номенклатура.Артикул) МЕЖДУ 1000 И 2000
УПОРЯДОЧИТЬ ПО
ВАЛ(Номенклатура.Артикул)
2. Сортировка по строковому коду
Если коды контрагентов хранятся как строки ("001", "002", ..., "010"), стандартная сортировка даст порядок: 001, 010, 002. Исправляем:
ВЫБРАТЬ
Контрагенты.Наименование
ИЗ
Справочник.Контрагенты КАК Контрагенты
УПОРЯДОЧИТЬ ПО
ВАЛ(Контрагенты.Код)
3. Агрегация по числовым значениям в строках
Задача: посчитать количество документов, где номер (строка) начинается с цифры 5.
ВЫБРАТЬ
КОЛИЧЕСТВО(*) КАК Количество
ИЗ
Документ.ЗаказПокупателя КАК Заказ
ГДЕ
ЛЕВ(Заказ.Номер, 1) = "5"
И ВАЛ(Заказ.Номер) > 5000
Что делать, если строка содержит не только цифры?
Если в строке есть префиксы (например, "ART-100"), используйте комбинацию ПРАВ() и НАЙТИ() для извлечения числовой части:
ВАЛ(СРЕД(Номенклатура.Артикул, НАЙТИ(Номенклатура.Артикул, "-") + 1))
Обработка ошибок преобразования
Если строка не может быть преобразована в число (например, содержит буквы), запрос завершится с ошибкой. Чтобы избежать этого, используйте конструкцию ВЫРАЗИТЬ или ПОПЫТКА (в новых версиях платформы).
1. Использование ВЫРАЗИТЬ
Позволяет подставить значение по умолчанию при ошибке:
ВЫБРАТЬ
ВЫРАЗИТЬ(ВАЛ(Номенклатура.Артикул) КАК Число(10,0)) КАК АртикулЧисло
Если преобразование не удалось, вернётся NULL.
2. Фильтрация "плохих" строк
Исключите записи, которые заведомо не могут быть числами:
ВЫБРАТЬ
Номенклатура.Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
НЕ Номенклатура.Артикул ПОДОБНО "%[^0-9]%" // Исключаем строки с нецифровыми символами
И ВАЛ(Номенклатура.Артикул) > 100
3. Логгирование ошибок
Для отладки полезно выводить строки, которые не удалось преобразовать:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Номенклатура.Артикул КАК НекорректныйАртикул
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
НЕ ПРЕДСТАВЛЯЕТСОБОЙЧИСЛО(Номенклатура.Артикул) // Функция проверяет, можно ли строку преобразовать в число
⚠️ Внимание: ФункцияПРЕДСТАВЛЯЕТСОБОЙЧИСЛО()появилась в платформе 1С:Предприятие 8.3.14. В более ранних версиях используйтеПОПЫТКА ... ИСКЛЮЧЕНИЕв программном коде.
FAQ: Частые вопросы
Можно ли сравнивать строку с числом напрямую, без преобразования?
Нет, это приведёт к ошибке. Система не выполняет неявное преобразование строк в числа в условиях ГДЕ. Всегда используйте явные функции (ВАЛ(), ЧИСЛО()).
Почему запрос с ВАЛ() работает медленно на большой таблице?
Функция ВАЛ() требует полного сканирования строк и их преобразования. Для ускорения:
- Создайте вычисляемое поле с числовым значением и проиндексируйте его.
- Используйте предварительную фильтрацию по строковым шаблонам (например,
НАЧИНАЕТСЯС).
Как преобразовать строку "1 234,56 руб." в число 1234.56?
Удалите все нецифровые символы (кроме разделителя дробной части) и замените разделители:
ВАЛ(СТРЗАМЕНИТЬ(
СТРЗАМЕНИТЬ(
СТРЗАМЕНИТЬ(Строка, " ", ""),
"руб.",
""
),
",",
"."
))
Что делать, если в строке есть буквенные префиксы (например, "PR-100")?
Извлеките числовую часть с помощью СРЕД() и НАЙТИ():
ВАЛ(СРЕД(
Артикул,
НАЙТИ(Артикул, "-") + 1
))
Или используйте регулярные выражения (в новых версиях платформы).
Как узнать, какие артикулы не преобразовались в числа?
Выполните запрос с проверкой:
ВЫБРАТЬ
Номенклатура.Артикул КАК НекорректныйАртикул
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
НЕ ПРЕДСТАВЛЯЕТСОБОЙЧИСЛО(Номенклатура.Артикул)
Или используйте конструкцию ПОПЫТКА ... ИСКЛЮЧЕНИЕ в программном коде.