В работе с 1С:Предприятие часто возникает задача сортировки строковых полей, которые на самом деле содержат числовые значения. Например, номера документов "001", "010", "002" или артикулы товаров "A100", "A20", "A3". Стандартная сортировка по алфавиту даст нелогичный результат: "001", "002", "010" превратится в "001", "010", "002". Эта проблема актуальна для отчетов, обработок и любых запросов, где важна правильная последовательность.
Решение требует преобразования строк в числа прямо в тексте запроса. Но здесь есть нюансы: от формата данных до особенностей синтаксиса 1С 8.3. В этой статье разберем все рабочие способы — от простых функций до сложных конструкций с регулярными выражениями. Вы узнаете, как избежать ошибок при сортировке смешанных данных (например, "Товар 1", "Товар 10", "Товар 2") и почему иногда лучше использовать виртуальные таблицы.
Особое внимание уделим производительности: неправильный подход может замедлить запрос в 10-100 раз. Например, применение ВЫРАЗИТЬ() ко всем строкам таблицы с миллионом записей сделает отчет непригодным для использования. Мы покажем оптимальные решения для больших баз данных и случаев, когда строки содержат не только цифры, но и буквы, дефисы или другие символы.
Для наглядности все примеры приведены с реальными сценариями: сортировка номера счета, артикулов в справочнике номенклатуры, версий документов. В конце статьи — чек-лист для быстрой проверки вашего запроса и FAQ по типичным ошибкам.
Почему стандартная сортировка строк ломает числовую последовательность
Проблема кроется в принципе сравнения строковых данных. Когда вы пишете в запросе УПОРЯДОЧИТЬ ПО НомерСтрокой, 1С сравнивает символы слева направо по их кодам в таблице Unicode. Цифра "0" имеет код 48, "1" — 49, и так далее. Поэтому строка "100" будет "меньше" чем "20", потому что первый символ "1" (код 49) меньше чем "2" (код 50).
Это приводит к абсурдным результатам:
- 📌
"1","10","100","2","20"— вместо ожидаемого"1", "2", "10", "20", "100" - 📌
"Арт.001","Арт.010","Арт.002"— вместо"Арт.001", "Арт.002", "Арт.010" - 📌
"Версия 1.10","Версия 1.2"— вместо"Версия 1.2", "Версия 1.10"
Еще хуже ситуация со строками, где числа перемежаны с текстом, например: "Заявка #10", "Заявка #2". Здесь без специальной обработки не обойтись. К счастью, в 1С есть инструменты для преобразования строк в числа прямо в запросе.
Важно понимать, что проблема не в самой 1С, а в фундаментальном различии между строковым и числовым сравнением. Даже в SQL или Excel вы получите тот же результат без явного приведения типов. Решение одно: заставить систему интерпретировать строки как числа на этапе сортировки.
Основные методы преобразования строк в числа в запросах
Существует три основных подхода к решению задачи. Каждый имеет свои плюсы и минусы в зависимости от структуры данных и требований к производительности.
1. Функция ВЫРАЗИТЬ() — самый простой и наглядный способ:
ВЫБРАТЬ
НомерКакСтрока,
ВЫРАЗИТЬ(НомерКакСтрока КАК ЧИСЛО(10,0)) КАК НомерКакЧисло
ИЗ
Документ.ЗаказыПокупателей
УПОРЯДОЧИТЬ ПО
НомерКакЧисло
2. Функция ЧИСЛО() — альтернатива для строк с "чистыми" числами:
ВЫБРАТЬ
Артикул,
ЧИСЛО(Артикул) КАК АртикулЧисло
ИЗ
Справочник.Номенклатура
УПОРЯДОЧИТЬ ПО
АртикулЧисло
3. Использование СТРОКА() с форматированием — для строк с ведущими нулями:
ВЫБРАТЬ
НомерДокумента,
СТРОКА(ВЫРАЗИТЬ(НомерДокумента КАК ЧИСЛО(10,0))) КАК НомерОтформатированный
ИЗ
Документ.РеализацияТоваровУслуг
УПОРЯДОЧИТЬ ПО
ВЫРАЗИТЬ(НомерОтформатированный КАК ЧИСЛО(10,0))
На практике ВЫРАЗИТЬ() работает стабильнее, так как явно указывает формат числа (количество знаков и разрядов после запятой). ЧИСЛО() может выдавать ошибки, если строка содержит посторонние символы. Для сложных случаев (например, "А100-B") потребуются регулярные выражения или обработка в коде 1С перед запросом.
Практические примеры для типичных задач
Рассмотрим реальные сценарии, с которыми сталкиваются разработчики 1С. Для каждого случая приведен оптимальный запрос и пояснения.
Пример 1: Сортировка номеров документов с ведущими нулями
Допустим, у вас номера документов хранятся как "000123", "001000", "000045". Нужно отсортировать их как 45, 123, 1000:
ВЫБРАТЬ
Номер КАК НомерДокумента
ИЗ
Документ.ПоступлениеТоваров
УПОРЯДОЧИТЬ ПО
ВЫРАЗИТЬ(Номер КАК ЧИСЛО(10,0))
Пример 2: Сортировка артикулов типа "ABC123"
Если артикулы имеют формат "PRD-001", "PRD-010", "PRD-002", извлеките числовую часть:
ВЫБРАТЬ
Артикул,
ВЫРАЗИТЬ(ПРАВ(Артикул, 3) КАК ЧИСЛО(10,0)) КАК ЧисловаяЧасть
ИЗ
Справочник.Номенклатура
УПОРЯДОЧИТЬ ПО
ЧисловаяЧасть
Пример 3: Сортировка версий ПО типа "1.10.2"
Для версий с несколькими числовыми компонентами ("1.10.2", "1.2.1") потребуется разбиение строки:
ВЫБРАТЬ
Версия,
ВЫРАЗИТЬ(ЛЕВ(Версия, НАЙТИ(Версия, ".") - 1) КАК ЧИСЛО(10,0)) КАК Major,
ВЫРАЗИТЬ(СРЕД(Версия, НАЙТИ(Версия, ".") + 1, НАЙТИ(Версия, ".", НАЙТИ(Версия, ".") + 1) - НАЙТИ(Версия, ".") - 1) КАК ЧИСЛО(10,0)) КАК Minor
ИЗ
Справочник.ПрограммныеПродукты
УПОРЯДОЧИТЬ ПО
Major, Minor
Для последнего примера лучше вынести логику в отдельную функцию на встроенном языке, если версий много. Это ускорит выполнение запроса.
Анализ формата данных (чистые числа/смешанные строки)|
Проверка на наличие недопустимых символов (буквы, знаки)|
Оценка производительности для больших таблиц|
Тестирование на крайних случаях (пустые строки, NULL)|
Сравнение результатов с ожидаемой последовательностью-->
Обработка сложных форматов: регулярные выражения и пользовательские функции
Когда строки содержат смешанные данные (например, "Товар #10 (упаковка)" или "2023-12-001"), стандартные функции 1С бессильны. Здесь помогут:
1. Регулярные выражения (доступны в 1С 8.3.14+):
ВЫБРАТЬ
Наименование,
ВЫРАЗИТЬ(РЕГВЫРАЗ(Наименование, "\d+") КАК ЧИСЛО(10,0)) КАК ИзвлеченноеЧисло
ИЗ
Справочник.Номенклатура
УПОРЯДОЧИТЬ ПО
ИзвлеченноеЧисло
2. Пользовательские функции на встроенном языке:
Создайте функцию, которая будет извлекать числовую часть и возвращать ее как число. Например:
Функция ИзвлечьЧислоИзСтроки(Строка)
Попытка
Возврат Число(СтрЗаменить(СтрЗаменить(Строка, " ", ""), НЕЧИСЛО, ""));
Исключение
Возврат 0;
КонецПопытки;
КонецФункции
Затем используйте ее в запросе через ВЫЧИСЛИТЬ:
ВЫБРАТЬ
Наименование,
ИзвлечьЧислоИзСтроки(Наименование) КАК ЧисловоеЗначение
ИЗ
Справочник.Номенклатура КАК Номенклатура
УПОРЯДОЧИТЬ ПО
ЧисловоеЗначение
3. Виртуальные таблицы — для сложных преобразований:
Если логика извлечения числа сложная, создайте виртуальную таблицу с предварительно рассчитанными значениями. Это ускорит повторные запросы.
Критическая ошибка: использование РЕГВЫРАЗ в больших запросах может привести к падению производительности в 50+ раз. Всегда тестируйте альтернативные подходы на реальных данных.
1. Ограничьте область применения регулярного выражения с помощью WHERE. 2. Используйте индексированные поля в условии отбора. 3. Для статических данных рассчитайте числовые значения заранее и храните в отдельном реквизите. 4. Разбейте сложный запрос на несколько простых с временными таблицами.Как ускорить запрос с РЕГВЫРАЗ
Оптимизация производительности: что замедляет запрос
Преобразование строк в числа — ресурсоемкая операция. Вот основные "тормоза" и способы их устранения:
| Проблема | Причина | Решение |
|---|---|---|
Медленная сортировка по ВЫРАЗИТЬ() |
Применение функции ко всем строкам таблицы | Добавить условие ГДЕ НЕ Наименование ПОДОБНО "%[^0-9]%" для фильтрации чисто числовых строк |
Зависание на РЕГВЫРАЗ() |
Сложные регулярные выражения для больших таблиц | Предварительно рассчитать значения в отдельном реквизите или виртуальной таблице |
| Ошибки приведения типов | Строки содержат недопустимые символы | Использовать ПОПЫТКА...ИСКЛЮЧЕНИЕ в пользовательской функции |
| Некорректная сортировка | Не учтены ведущие нули или разделители | Нормализовать формат строк перед сортировкой (например, СТРОКА(Число) с фиксированной длиной) |
Для таблиц с более чем 10 000 записей рекомендуется:
- 🔧 Предварительно рассчитывать числовые эквиваленты строк в отдельных реквизитах
- 🔧 Использовать материализованные представления (в PostgreSQL или MS SQL)
- 🔧 Разбивать запрос на части с временными таблицами
- 🔧 Отказываться от сортировки по вычисляемым полям в пользу индексированных
Например, если вам часто нужна сортировка артикулов как чисел, добавьте в справочник Номенклатура реквизит АртикулЧисловой (тип Число) и заполняйте его при записи элемента. Тогда запрос упростится до:
ВЫБРАТЬ
Артикул, Наименование
ИЗ
Справочник.Номенклатура
УПОРЯДОЧИТЬ ПО
АртикулЧисловой
Для отладки медленных запросов используйте план выполнения в консоли запросов (кнопка "План"). Он покажет, на каком этапе происходит торможение — на чтении данных или на сортировке.
Типичные ошибки и как их избежать
Даже опытные разработчики допускают ошибки при сортировке строк как чисел. Вот самые распространенные:
1. Игнорирование NULL-значений
Если поле может быть пустым, добавьте обработку:
ВЫБРАТЬ
НомерДокумента,
ЕСЛИ НомерДокумента ЕСТЬ NULL ТОГДА 0 ИНАЧЕ ВЫРАЗИТЬ(НомерДокумента КАК ЧИСЛО(10,0)) КОНЕЦ КАК НомерЧисло
ИЗ
Документ.ЗаказыПокупателей
2. Неучтенные региональные настройки
В некоторых локалях в качестве разделителя используется запятая вместо точки. Это ломает ВЫРАЗИТЬ() для чисел с дробной частью. Решение:
ВЫБРАЗИТЬ(СТРЗАМЕНИТЬ(СтрокаЧисла, ",", ".") КАК ЧИСЛО(10,2))
3. Переполнение числового типа
Если строка содержит число больше чем 2 147 483 647 (максимум для ЧИСЛО(10,0)), используйте ЧИСЛО(15,0) или ЧИСЛО(20,0).
4. Сортировка по вычисляемому полю в подзапросе
Это многократно увеличивает время выполнения. Лучше вынести вычисления в основной запрос или использовать ВРЕМЕННАЯ ТАБЛИЦА.
⚠️ Внимание: При использовании ВЫРАЗИТЬ() для полей с индексами 1С может проигнорировать индексы и выполнить полное сканирование таблицы. Проверяйте план выполнения!
Еще одна распространенная ошибка — попытка отсортировать строки типа "1.10" и "1.2" как числа без учета разрядов. В этом случае ВЫРАЗИТЬ(Строка КАК ЧИСЛО(10,2)) даст корректный результат, а ЧИСЛО(Строка) может округлить значения.
Альтернативные подходы: когда запрос не лучшее решение
Иногда сортировку строк как чисел целесообразнее реализовать не в запросе, а на уровне 1С-кода. Это актуально для:
- 📊 Отчетов с сложной логикой формирования данных
- 📊 Динамических списков, где требуется интерактивная сортировка
- 📊 Обработок с большим объемом данных, где производительность критична
Пример 1: Сортировка в коде после получения данных
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номер КАК НомерСтрокой
|ИЗ
| Документ.ЗаказыПокупателей";
Результат = Запрос.Выполнить().Выгрузить();
// Сортировка в памяти
Сортировка = Новый Структура("НомерЧисло", "Число");
МассивДляСортировки = Новый Массив;
Для Каждого Строка Из Результат Цикл
Попытка
Число = Число(Строка.НомерСтрокой);
МассивДляСортировки.Добавить(Строка);
Исключение
// Игнорируем строки, которые не удается преобразовать
КонецПопытки;
КонецЦикла;
МассивДляСортировки.СортироватьПоПолю("НомерЧисло");
Пример 2: Использование объекта "ТаблицаЗначений"
Если данных немного, удобно работать с ТаблицаЗначений:
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("НомерСтрокой");
Таблица.Колонки.Добавить("НомерЧисло", Новый ОписаниеТипов("Число"));
// Заполнение таблицы с преобразованием
Для Каждого Строка Из РезультатЗапроса Цикл
НоваяСтрока = Таблица.Добавить();
НоваяСтрока.НомерСтрокой = Строка.Номер;
Попытка
НоваяСтрока.НомерЧисло = Число(Строка.Номер);
Исключение
НоваяСтрока.НомерЧисло = 0;
КонецПопытки;
КонецЦикла;
Таблица.Сортировать("НомерЧисло");
Пример 3: Клиент-серверный вариант для больших данных
Для ускорения обработки на сервере:
&НаСервере
Функция ПолучитьОтсортированныеДанные()
Запрос = Новый Запрос;
// ... выполнение запроса ...
Результат = Запрос.Выполнить().Выгрузить();
Возврат ОбщегоМодуля.СортировкаДанных.ОтсортироватьПоЧисловомуПолю(Результат, "НомерСтрокой");
КонецФункции
Преимущество подхода в коде — гибкость. Вы можете:
- 🔹 Обрабатывать ошибки преобразования
- 🔹 Применять сложные алгоритмы сортировки (например, по нескольким числовым частям)
- 🔹 Кэшировать результаты для повторного использования
⚠️ Внимание: При сортировке в коде для больших массивов данных (более 10 000 строк) используйте ФоновоеЗадание, чтобы не блокировать интерфейс пользователя.
FAQ: Ответы на частые вопросы
Можно ли отсортировать строки как числа без изменения запроса?
Да, если вы используете динамический список или отчет на СКД. В настройках сортировки можно указать выражение для преобразования строк в числа. Например, в СКД для поля Номер задайте выражение:
ВЫРАЗИТЬ(Номер КАК ЧИСЛО(10,0))
Это позволит сортировать данные корректно без изменения исходного запроса.
Почему при использовании ЧИСЛО() возникает ошибка "Некорректное число"?
Функция ЧИСЛО() строго проверяет формат строки. Ошибка возникает если:
- Строка пустая или содержит только пробелы
- Строка содержит недопустимые символы (буквы, знаки, кроме "." и ",")
- Число слишком большое для типа Число (более 1.7e+308)
- Используется неподходящий разделитель дробной части (например, точка вместо запятой для текущей локали)
Решение: используйте ВЫРАЗИТЬ() с явным указанием формата или обрабатывайте исключения через ПОПЫТКА...ИСКЛЮЧЕНИЕ.
Как отсортировать строки вида "А100", "А20", "А3" по числовой части?
Используйте комбинацию строковых функций для извлечения числовой части:
ВЫБРАТЬ
Код,
ВЫРАЗИТЬ(СРЕД(Код, НАЙТИ(Код, "А") + 1) КАК ЧИСЛО(10,0)) КАК ЧисловаяЧасть
ИЗ
Справочник.Номенклатура
УПОРЯДОЧИТЬ ПО
ЧисловаяЧасть
Для более сложных форматов (например, "ABC-100-XYZ") применяйте регулярные выражения:
ВЫРАЗИТЬ(РЕГВЫРАЗ(Код, "(?<=\D)\d+(?=\D)") КАК ЧИСЛО(10,0))
Почему сортировка работает медленно на большой таблице?
Основные причины:
- Применение функции ко всем строкам таблицы (например,
ВЫРАЗИТЬ()для миллиона записей) - Отсутствие индексов на полях, используемых в условии
ГДЕ - Сложные вычисления в секции
УПОРЯДОЧИТЬ ПО - Использование
РЕГВЫРАЗ()без ограничений
Решения:
- Добавляйте условие
ГДЕдля фильтрации данных перед сортировкой - Создавайте временные таблицы с предварительно рассчитанными значениями
- Используйте материализованные представления в SQL-базе
- Для статических данных рассчитывайте числовые эквиваленты заранее и храните в отдельных полях
Можно ли отсортировать строки как числа в отчете на СКД без изменения схемы?
Да, в настройках поля сортировки укажите выражение для преобразования. Например:
- Откройте схему компоновки данных
- Перейдите на закладку "Настройки"
- В дереве настроек выберите поле, по которому нужна сортировка
- В свойствах поля найдите параметр "Выражение для сортировки"
- Укажите выражение:
ВЫРАЗИТЬ([НомерДокумента] КАК ЧИСЛО(10,0))
Это позволит сортировать данные корректно без изменения исходного запроса в схеме.