Разберем классическую ситуацию, с которой сталкиваются разработчики 1С при работе с запросами. Допустим, у нас есть строковый реквизит (например, номер или код), в который пользователи заносят только цифры. Проблема заключается в том, что при стандартной сортировке (УПОРЯДОЧИТЬ ПО) платформа выстраивает строки по алфавиту, а не по математическим правилам. В результате мы получаем нелогичный для пользователя порядок: 1, 10, 11, 110, 120, 2, 5. А нам необходимо вывести данные по порядку возрастания числовых значений: 1, 2, 5, 10, 11, 110, 120.
Многие разработчики сначала пытаются решить проблему "в лоб" с помощью конструкции ВЫРАЗИТЬ(Сотрудники.Реквизит1 КАК ЧИСЛО(10,0)). Однако проанализируем этот подход: он не сработает. Согласно синтаксис-помощнику (СП) 1С, функция ВЫРАЗИТЬ предназначена для приведения типов (например, выделения конкретного типа из составного типа данных), а не для динамического преобразования строки в число. Платформа выдаст ошибку о несовместимых типах. Выясним причину: типы данных в базе строго типизированы, и СУБД не умеет налету менять тип поля при простой выборке таким образом.
Давайте подробно рассмотрим рабочие и проверенные способы решения этой задачи, начиная от современных и заканчивая обходными путями для старых конфигураций.
Самое изящное и производительное решение появилось в современных релизах платформы. Начиная с версии 8.3.18, в языке запросов стали доступны функции работы со строками, в том числе функция СТРДЛИНА(). Посмотрим на пример реализации.
Чтобы отсортировать строковый реквизит, состоящий только из цифр, как число, нам достаточно использовать многоуровневую сортировку: сначала по длине строки, а затем по самому строковому значению. Разберем по шагам логику:
В тексте запроса это будет выглядеть следующим образом:
ВЫБРАТЬ
Сотрудники.Наименование КАК Наименование,
Сотрудники.Реквизит1 КАК Реквизит1
ИЗ
Справочник.Сотрудники КАК Сотрудники
УПОРЯДОЧИТЬ ПО
СТРДЛИНА(Сотрудники.Реквизит1),
Сотрудники.Реквизит1
Важное преимущество: при таком подходе вам не придется выгружать данные в таблицы значений или менять структуру конфигурации, добавляя новые реквизиты.
Если ваш запрос используется для вывода данных в отчет на базе СКД, то проблему можно решить вообще не трогая сам текст запроса. СКД обладает более широкими возможностями по преобразованию типов благодаря языку выражений.
Рассмотрим подробнее порядок действий:
РеквизитЧислом.Число(Реквизит1). Язык выражений СКД прекрасно умеет конвертировать строки в числа.Если в строке могут изредка встречаться неразрывные пробелы или буквы (из-за которых встроенная функция выдаст ошибку), в выражении СКД можно вызвать экспортную функцию из общего модуля, которая предварительно очистит строку от "мусора" и безопасно конвертирует ее. Отчет выведет данные строго по числовому порядку.
Проанализируем ситуацию, когда у нас старая платформа (до 8.3.18) и нет СКД. Классическим рабочим вариантом является постобработка результата запроса. Мы разбиваем задачу на три этапа.
Посмотрим на пример кода:
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
РезультатЗапроса.Колонки.Добавить("ЧисловойРеквизит", Новый ОписаниеТипов("Число"));
Для каждого СтрокаТЗ Из РезультатЗапроса Цикл
Попытка
СтрокаТЗ.ЧисловойРеквизит = Число(СокрЛП(СтрокаТЗ.Реквизит1));
Исключение
СтрокаТЗ.ЧисловойРеквизит = 0;
КонецПопытки;
КонецЦикла;
РезультатЗапроса.Сортировать("ЧисловойРеквизит ВОЗР");
Еще один концептуальный метод решения проблемы строковой сортировки — приведение всех строк к одинаковой длине путем добавления нулей слева (лидирующих нулей). Строки вида "000001", "000110" и "000120" сортируются в алфавитном порядке точно так же, как и числа по возрастанию.
Если вы можете изменить данные в базе один раз программно, это самый быстрый для запросов путь. Мы берем строку, прибавляем к ней много нулей спереди, а затем берем правые символы на заданную длину.
Пример программного приведения длины:
// Приводим к длине 14 символов
НовоеЗначение = Прав("00000000000000" + ИсходнаяСтрока, 14);
Важное примечание: Если изменять данные в базе нельзя (типовая конфигурация), разработчики иногда пытаются реализовать дополнение нулями прямо в тексте запроса. В старых платформах для этого строится громоздкое условие ВЫБОР КОГДА в связке с функцией ПОДСТРОКА(): запрос проверяет, является ли пустой строкой второй символ, третий и так далее, искусственно вычисляя длину и приклеивая нужное количество нулей (например, "000" + Сотрудники.Реквизит1). Код получается объемным и тяжело читаемым, но позволяет выполнить задачу исключительно силами СУБД, без использования ТЗ.