Как отсортировать результат запроса по длине строки в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С:Предприятие часто возникает задача упорядочивания данных не по алфавиту, а по количеству символов в строковом поле. Например, это может потребоваться при формировании прайс-листов, анализе артикулов или обработке характеристик номенклатуры. Рассмотрим подробно все существующие способы решения этой задачи, начиная от современных возможностей платформы и заканчивая хитростями для старых версий.

Способ 1: Использование встроенной функции ДЛИНАСТРОКИ() (для платформы 8.3.20 и выше)

Начиная с версии платформы 8.3.20, разработчики 1С добавили долгожданную встроенную функцию ДЛИНАСТРОКИ() непосредственно в язык запросов. Это наиболее правильный и производительный метод решения задачи на сегодняшний день. Разберем его применение на примере.

Предположим, нам нужно получить список комплектности из справочника МаркировкаТовара, отсортированный от самой длинной строки к самой короткой. Проанализируем следующий код запроса:


ВЫБРАТЬ
    МаркировкаТовара.Комплектность КАК Комплектность,
    ДЛИНАСТРОКИ(МаркировкаТовара.Комплектность) КАК ДлинаПоля
ИЗ
    Справочник.МаркировкаТовара КАК МаркировкаТовара
УПОРЯДОЧИТЬ ПО
    ДлинаПоля УБЫВ

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

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

Способ 2: Реализация для старых платформ (через конструкцию ВЫБОР)

Если вы работаете на версии платформы ниже 8.3.20, прямой функции получения длины в запросе нет. В этом случае нам придется проявить изобретательность. Разберем метод, основанный на последовательной проверке наличия символов в определенных позициях с помощью функции ПОДСТРОКА() и оператора ВЫРАЗИТЬ().

Посмотрим на пример кода, который определяет длину строки до 6 символов:


ВЫБРАТЬ
    Справочник1.Наименование,
    ВЫБОР
        КОГДА ПОДСТРОКА(ВЫРАЗИТЬ(Справочник1.Наименование КАК СТРОКА(6)), 6, 1) <> "" ТОГДА 6
        КОГДА ПОДСТРОКА(ВЫРАЗИТЬ(Справочник1.Наименование КАК СТРОКА(5)), 5, 1) <> "" ТОГДА 5
        КОГДА ПОДСТРОКА(ВЫРАЗИТЬ(Справочник1.Наименование КАК СТРОКА(4)), 4, 1) <> "" ТОГДА 4
        КОГДА ПОДСТРОКА(ВЫРАЗИТЬ(Справочник1.Наименование КАК СТРОКА(3)), 3, 1) <> "" ТОГДА 3
        ИНАЧЕ 0
    КОНЕЦ КАК ДлинаНаименования
ИЗ
    Справочник.Номенклатура КАК Справочник1
УПОРЯДОЧИТЬ ПО
    ДлинаНаименования УБЫВ

Проанализируем ситуацию: мы идем от обратного — проверяем самый дальний возможный символ. Если в шестой позиции что-то есть (строка не пустая), значит длина как минимум 6. Если там пусто, проверяем пятую позицию и так далее. Этот метод громоздкий, но рабочий. Основной минус — необходимость заранее знать или ограничивать максимальную длину исследуемой строки.

Способ 3: Оптимизированный "бинарный" поиск в запросе

Если строка может быть длинной (например, до 150 символов), писать 150 условий КОГДА крайне неэффективно. В таком случае мы можем применить принцип степеней двойки (бинарный поиск), чтобы сократить объем кода. Мы проверяем блоки по 64, 32, 16 символов, постепенно сужая диапазон.

Однако чаще всего для таких задач на старых платформах рекомендуется использовать метод "суммирования весов", где каждое условие ВЫБОР прибавляет единицу, если символ в данной позиции существует. Но даже этот метод создает серьезную нагрузку на SQL-сервер.

Способ 4: Использование Системы компоновки данных (СКД)

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

Разберем шаги настройки:

  1. Откроем схему компоновки данных.
  2. Перейдем на вкладку Вычисляемые поля.
  3. Добавим новое поле с заголовком "Длина", а в колонке "Выражение" напишем: ДлинаСтроки(Комплектность).
  4. На вкладке Настройки в разделе "Сортировка" выберем наше новое поле "Длина" и установим направление "По убыванию".

Этот метод хорош тем, что 1С сама берет на себя вычисление длины, корректно обрабатывая значения NULL и пустые строки.

Способ 5: Постобработка в Таблице Значений

Иногда запрос выполняется слишком долго из-за сложных вычислений в блоке УПОРЯДОЧИТЬ ПО. В этом случае мы можем рассмотреть вариант с обработкой результата в оперативной памяти сервера приложений. Посмотрим на алгоритм:

  1. Выполняем простой запрос без сортировки по длине.
  2. Выгружаем результат в ТаблицаЗначений.
  3. Добавляем в таблицу новую колонку Длина (тип Число).
  4. В цикле обходим таблицу и заполняем колонку с помощью функции СтрДлина().
  5. Вызываем метод Сортировать() для таблицы значений.

РезультатЗапроса = Запрос.Выполнить();
ТЗ = РезультатЗапроса.Выгрузить();
ТЗ.Колонки.Добавить("Длина", Новый ОписаниеТипов("Число"));

Для Каждого СтрокаТЗ Из ТЗ Цикл
    СтрокаТЗ.Длина = СтрДлина(СтрокаТЗ.Комплектность);
КонецЦикла;

ТЗ.Сортировать("Длина УБЫВ");

Этот метод часто оказывается быстрее на больших объемах данных (сотни тысяч строк), так как SQL-серверу не приходится выполнять "тяжелую" сортировку по вычисляемому полю, которая всегда приводит к полному сканированию таблицы (Full Scan), игнорируя индексы.

Производительность и важные рекомендации

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

Рекомендация для высоконагруженных систем: если сортировка по длине строки нужна постоянно, лучше всего создать в справочнике дополнительный числовой реквизит ДлинаНаименования. В модуле объекта в обработчике ПередЗаписью пропишите расчет этого поля:


Процедура ПередЗаписью(Отказ)
    ДлинаНаименования = СтрДлина(Наименование);
КонецПроцедуры

Не забудьте установить индексирование для этого реквизита. В этом случае ваш запрос будет отрабатывать мгновенно, так как SQL-сервер будет использовать готовый индекс по числу, а не вычислять длину каждой строки на лету.

Также помните о различиях в СУБД: MS SQL Server при расчете длины (функция LEN) может игнорировать пробелы в конце строки, тогда как PostgreSQL (функция CHAR_LENGTH) их учитывает. Чтобы результаты были предсказуемыми, всегда используйте функцию СОКРП() перед определением длины, если это критично для вашей бизнес-логики.

← На главную