Разработка и Конфигурация · 11 мин
Сортировка строки как числа в запросе 1С
Как в запросе 1С отсортировать строковое поле как число: приведение типов, ВЫРАЗИТЬ, ПОДСТРОКА, сортировка кодов и номеров документов с примерами кода.
Строковые поля в запросах 1С сортируются по алфавиту, а не по числовому значению. Поэтому коды «1», «2», «10», «11» выстроятся в последовательность «1», «10», «11», «2» — лексикографически, а не по величине. Это классическая проблема при выводе номеров документов, кодов справочников, артикулов и любых реквизитов строкового типа, где фактически хранятся числа.
Решить задачу можно несколькими способами: привести строку к числу функцией ВЫРАЗИТЬ, дополнить строку ведущими нулями, отсортировать по длине и затем по значению, либо вынести сортировку из запроса в таблицу значений. У каждого варианта есть ограничения по типам данных, производительности и поддержке в разных СУБД, поэтому выбор зависит от того, что именно хранится в поле.
Ниже разобраны рабочие приёмы с примерами кода на встроенном языке запросов 1С, условия их применения, типичные ошибки и способы проверить корректность результата.
Почему строки сортируются «неправильно»
Строковый тип в 1С и в СУБД сравнивается посимвольно по кодам символов. Символ «1» меньше символа «2», поэтому строка «10» оказывается раньше строки «2»: сравнение заканчивается уже на первом символе. Длина строки при таком сравнении не учитывается, пока не совпали все начальные символы.
Это поведение не ошибка платформы, а стандартное правило лексикографической сортировки. Проблема возникает только тогда, когда разработчик хранит числа в строковом реквизите — например, номер документа, артикул, код элемента справочника или выгруженное из внешней системы значение.
Особенно заметно это на номерах документов: у документов номер всегда строковый, и запрос с простым УПОРЯДОЧИТЬ ПО Номер выдаст «000001», «000010», «000002», если нумерация не дополнена нулями до одинаковой длины. В типовых конфигурациях префиксация и фиксированная длина номера частично маскируют проблему, но при смешанных префиксах она проявляется снова.
Способ 1: приведение к числу через ВЫРАЗИТЬ
Самый прямой вариант — преобразовать строку в число прямо в секции упорядочивания. Функция ВЫРАЗИТЬ приводит значение к указанному типу:
ВЫБРАТЬ
Товары.Код КАК Код,
Товары.Наименование КАК Наименование
ИЗ
Справочник.Товары КАК Товары
УПОРЯДОЧИТЬ ПО
ВЫРАЗИТЬ(Товары.Код КАК ЧИСЛО(10, 0))
Результат: «1», «2», «10», «25», «100» — в правильном числовом порядке. Длину числа указывайте с запасом относительно максимального значения в поле, чтобы избежать переполнения при приведении.
Ключевое ограничение: если в поле встретится значение, которое нельзя преобразовать в число (буквы, дефисы, пробелы), поведение зависит от СУБД. В файловом варианте и на MS SQL Server запрос может завершиться ошибкой, на PostgreSQL — тоже выдаст ошибку преобразования. Поэтому способ безопасен только тогда, когда вы уверены в содержимом поля.
Способ 2: сортировка по длине строки, затем по значению
Для строк, состоящих только из цифр без ведущих нулей, работает элегантный приём без преобразования типов: сначала упорядочить по длине строки, затем по самой строке. Любое число из двух цифр больше любого числа из одной цифры, а внутри одинаковой длины лексикографический порядок совпадает с числовым.
УПОРЯДОЧИТЬ ПО
ДЛИНАСТРОКИ(Товары.Код),
Товары.Код
Порядок получится «1», «2», «10», «25», «100» — как при числовой сортировке. Метод не требует приведения типов и не падает с ошибкой, но ломается на ведущих нулях («007» даст длину 3 и встанет рядом с трёхзначными числами) и на смешанных символах.
Этот приём удобен для номеров и кодов, где формат свободный, но гарантированно цифровой. Он также обычно быстрее приведения типов на больших выборках, так как ДЛИНАСТРОКИ вычисляется дешевле, чем преобразование в число.
Способ 3: дополнение ведущими нулями
Если формат данных можно контролировать, надёжнее всего хранить коды фиксированной длины с ведущими нулями: «0001», «0002», «0010», «0100». Тогда обычная строковая сортировка даёт правильный числовой порядок без каких-либо преобразований в запросе.
Дополнить значение нулями можно и на лету, в самом запросе, обрезав конкатенацию справа:
УПОРЯДОЧИТЬ ПО
ПОДСТРОКА("0000000000" + Товары.Код,
ДЛИНАСТРОКИ("0000000000" + Товары.Код) - 9, 10)
Здесь к коду слева добавляется десять нулей, а затем берутся последние десять символов — получается строка фиксированной длины. Приём рабочий, но громоздкий и медленный на больших таблицах: строковые операции выполняются для каждой строки выборки, индексы не используются.
На практике правильнее решать задачу на уровне данных: включить для справочника или документа автонумерацию с фиксированной длиной, либо при записи элемента дополнять код процедурой форматирования. Тогда запросы остаются простыми и быстрыми.
Сортировка номеров документов с префиксами
Номер документа в 1С — строка, часто содержащая префикс базы или организации: «БП00-000123», «00ЦК-000045». Простое приведение к числу здесь невозможно. Типовой подход — отрезать префикс и сортировать по числовой части:
ВЫБРАТЬ
Реализация.Номер КАК Номер,
Реализация.Дата КАК Дата
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
УПОРЯДОЧИТЬ ПО
ВЫРАЗИТЬ(ПОДСТРОКА(Реализация.Номер, 7, 6) КАК ЧИСЛО(10, 0))
Здесь ПОДСТРОКА берёт символы начиная с седьмого — позицию подбирайте под фактическую длину префикса в вашей базе. Если префиксы разной длины, надёжнее сортировать документы по дате и моменту времени, а не по номеру: номер — пользовательский реквизит, а не гарант хронологии.
Как выбрать действие
Альтернатива: сортировка после выборки
Если логика сложная — смешанные форматы, исключения, разные правила для разных групп — разумнее выполнить сортировку не в запросе, а в таблице значений после выгрузки. Добавьте колонку с числовым представлением и отсортируйте по ней:
ТЗ = Запрос.Выполнить().Выгрузить();
ТЗ.Колонки.Добавить("КодЧислом", Новый ОписаниеТипов("Число"));
Для Каждого Строка Из ТЗ Цикл
Попытка
Строка.КодЧислом = Число(Строка.Код);
Исключение
Строка.КодЧислом = 0;
КонецПопытки;
КонецЦикла;
ТЗ.Сортировать("КодЧислом");
Преимущество подхода — полный контроль: функция Число() встроенного языка в сочетании с Попытка/Исключение позволяет обработать нечисловые значения по своему правилу, а не падать с ошибкой. Недостаток — вся выборка загружается в память, что неприемлемо для очень больших таблиц.
Для динамических списков и СКД сортировку после выборки применять нельзя — там порядок формируется только запросом. В этих случаях возвращайтесь к приведению типов или сортировке по длине.
Перед выбором способа выполните контрольный запрос: выберите различные значения поля и проверьте, есть ли среди них нечисловые. Одна запись с буквой в коде способна обрушить отчёт с ВЫРАЗИТЬ(КАК ЧИСЛО) в самый неподходящий момент — у пользователя, а не у разработчика.
Проверка результата и типичные ошибки
После внедрения сортировки проверьте результат на граничных значениях: минимальное и максимальное число, значения разной длины, записи с ведущими нулями и пустые строки. Пустая строка при приведении к числу на части СУБД даёт ошибку, на других — NULL, который при сортировке по возрастанию встанет в начало или конец выборки в зависимости от СУБД.
Отдельная ошибка — применять числовую сортировку там, где пользователь ожидает алфавитную. Если коды содержат и числа, и буквенные обозначения, смешанная сортировка может выглядеть для пользователя как беспорядок. Согласуйте ожидаемый порядок до реализации.
Как проверить результат
Идут по возрастанию как числа
10 стоит раньше 2 — сортировка осталась строковой
Запрос выполняется, такие записи обработаны по заданному правилу
Ошибка преобразования типа при выполнении
Сопоставимо с запросом без выражений
Резкий рост времени — выражение отключило индекс
Попадают в начало или конец предсказуемо
Ошибка или непредсказуемое положение в выборке
FAQ
Можно ли отсортировать строку как число в динамическом списке?
Да, через произвольный текст запроса динамического списка: добавьте в секцию УПОРЯДОЧИТЬ ПО выражение ВЫРАЗИТЬ(Поле КАК ЧИСЛО) или пару ДЛИНАСТРОКИ(Поле), Поле. Учтите, что пользовательская сортировка по колонке тогда будет работать по строковому правилу, если её не переопределить.
Что делать, если в поле встречаются буквы, а числовой порядок нужен для числовой части?
Разделите значение на части: отсортируйте сначала по нечисловому признаку (например, по префиксу), затем по числовой части, извлечённой через ПОДСТРОКУ. Если структура значений нерегулярная, надёжнее выгрузить результат в таблицу значений и сортировать встроенным языком с обработкой исключений.
Почему ВЫРАЗИТЬ(Поле КАК ЧИСЛО) выдаёт ошибку, хотя все значения выглядят числовыми?
Частые скрытые причины — пробелы в начале или конце строки, неразрывные пробелы, пустые строки и символы-невидимки, попавшие при обмене данными. Проверьте данные запросом с условием на длину после сокращения пробелов: ДЛИНАСТРОКИ(Поле) <> ДЛИНАСТРОКИ(СОКРЛП(Поле)) покажет проблемные записи.
Какой способ быстрее на больших таблицах?
Быстрее всего хранить данные в правильном типе и сортировать по индексированному полю без выражений. Из вычисляемых вариантов сортировка по ДЛИНАСТРОКИ обычно дешевле приведения к числу, а оба варианта быстрее конкатенации с ПОДСТРОКОЙ. Любое выражение в упорядочивании отключает использование индекса по этому полю.
Работает ли приведение строки к числу в СКД?
Да, функции языка запросов ВЫРАЗИТЬ, ДЛИНАСТРОКИ и ПОДСТРОКА доступны в запросе набора данных СКД. Добавьте выражение в поле набора и настройте сортировку по нему на закладке «Настройки» схемы компоновки. Альтернатива — вычисляемое поле с приведением на уровне запроса набора.
Как отсортировать номера документов разной длины и с разными префиксами?
Единого надёжного способа через номер нет — префиксы разной длины делают ПОДСТРОКУ с фиксированной позицией некорректной. Практичные варианты: сортировка по дате и ссылке (хронологический порядок) или по дате и номеру. Если нужен именно числовой порядок номеров, нормализуйте номера при записи документа, приведя их к единому формату.
Что важно запомнить
Строки в запросе 1С сортируются посимвольно, поэтому числа в строковых полях требуют специальной обработки: ВЫРАЗИТЬ(КАК ЧИСЛО) для чисто числовых данных, сортировка по длине и значению для цифровых кодов без нулей, вынос в таблицу значений для сложных случаев. Любое выражение в упорядочивании отключает индексы — проверяйте производительность на рабочих объёмах.