К статье
Практический материал

Разработка и Конфигурация · 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, который при сортировке по возрастанию встанет в начало или конец выборки в зависимости от СУБД.

Типичные ошибки
01
Приведение к числу без проверки данных — запрос падает на первой записи с буквой или дефисом
02
Слишком маленькая разрядность ЧИСЛО(5,0) — переполнение и ошибка при больших значениях кода
03
Сортировка по длине для кодов с ведущими нулями — «007» уходит к трёхзначным числам
04
Ожидание работы индекса — выражения в УПОРЯДОЧИТЬ ПО отключают индексы, отчёт тормозит на больших таблицах
05
ПОДСТРОКА с жёсткой позицией префикса — при смене префикса базы сортировка молча ломается

Отдельная ошибка — применять числовую сортировку там, где пользователь ожидает алфавитную. Если коды содержат и числа, и буквенные обозначения, смешанная сортировка может выглядеть для пользователя как беспорядок. Согласуйте ожидаемый порядок до реализации.

Контрольные точки

Как проверить результат

Порядок значений 1, 2, 10, 100
Норма

Идут по возрастанию как числа

Тревожный признак

10 стоит раньше 2 — сортировка осталась строковой

Записи с буквами или дефисами в поле
Норма

Запрос выполняется, такие записи обработаны по заданному правилу

Тревожный признак

Ошибка преобразования типа при выполнении

Время выполнения на рабочем объёме данных
Норма

Сопоставимо с запросом без выражений

Тревожный признак

Резкий рост времени — выражение отключило индекс

Пустые строки в поле
Норма

Попадают в начало или конец предсказуемо

Тревожный признак

Ошибка или непредсказуемое положение в выборке

FAQ

Можно ли отсортировать строку как число в динамическом списке?

Да, через произвольный текст запроса динамического списка: добавьте в секцию УПОРЯДОЧИТЬ ПО выражение ВЫРАЗИТЬ(Поле КАК ЧИСЛО) или пару ДЛИНАСТРОКИ(Поле), Поле. Учтите, что пользовательская сортировка по колонке тогда будет работать по строковому правилу, если её не переопределить.

Что делать, если в поле встречаются буквы, а числовой порядок нужен для числовой части?

Разделите значение на части: отсортируйте сначала по нечисловому признаку (например, по префиксу), затем по числовой части, извлечённой через ПОДСТРОКУ. Если структура значений нерегулярная, надёжнее выгрузить результат в таблицу значений и сортировать встроенным языком с обработкой исключений.

Почему ВЫРАЗИТЬ(Поле КАК ЧИСЛО) выдаёт ошибку, хотя все значения выглядят числовыми?

Частые скрытые причины — пробелы в начале или конце строки, неразрывные пробелы, пустые строки и символы-невидимки, попавшие при обмене данными. Проверьте данные запросом с условием на длину после сокращения пробелов: ДЛИНАСТРОКИ(Поле) <> ДЛИНАСТРОКИ(СОКРЛП(Поле)) покажет проблемные записи.

Какой способ быстрее на больших таблицах?

Быстрее всего хранить данные в правильном типе и сортировать по индексированному полю без выражений. Из вычисляемых вариантов сортировка по ДЛИНАСТРОКИ обычно дешевле приведения к числу, а оба варианта быстрее конкатенации с ПОДСТРОКОЙ. Любое выражение в упорядочивании отключает использование индекса по этому полю.

Работает ли приведение строки к числу в СКД?

Да, функции языка запросов ВЫРАЗИТЬ, ДЛИНАСТРОКИ и ПОДСТРОКА доступны в запросе набора данных СКД. Добавьте выражение в поле набора и настройте сортировку по нему на закладке «Настройки» схемы компоновки. Альтернатива — вычисляемое поле с приведением на уровне запроса набора.

Как отсортировать номера документов разной длины и с разными префиксами?

Единого надёжного способа через номер нет — префиксы разной длины делают ПОДСТРОКУ с фиксированной позицией некорректной. Практичные варианты: сортировка по дате и ссылке (хронологический порядок) или по дате и номеру. Если нужен именно числовой порядок номеров, нормализуйте номера при записи документа, приведя их к единому формату.

Итог

Что важно запомнить

Строки в запросе 1С сортируются посимвольно, поэтому числа в строковых полях требуют специальной обработки: ВЫРАЗИТЬ(КАК ЧИСЛО) для чисто числовых данных, сортировка по длине и значению для цифровых кодов без нулей, вынос в таблицу значений для сложных случаев. Любое выражение в упорядочивании отключает индексы — проверяйте производительность на рабочих объёмах.