При выгрузке данных из запроса разработчики нередко сталкиваются с ситуацией, когда числовые данные хранятся в строковом реквизите (например, в дополнительных реквизитах и сведениях). В языке запросов 1С конструкция ВЫРАЗИТЬ() не выполняет преобразование типа из строки в число — она предназначена только для сужения составных типов или изменения длины. В результате попытка упорядочить такие строки приводит к лексикографической сортировке (где строка "10" оказывается раньше строки "2").
Для решения задачи результат запроса часто выгружают в объект ТаблицаЗначений, чтобы программно привести типы и выполнить сортировку. Рассмотрим типичные ошибки, возникающие при реализации этого алгоритма, и разберем по шагам правильные способы их устранения.
Проанализируем исходный фрагмент кода, в котором возникает ошибка выполнения:
ВыгрузкаТовары = Запрос.Выполнить();
ТЗ = ВыгрузкаТовары.Выгрузить();
Для Каждого Стр Из ТЗ Цикл
ТЗ.Колонки.Добавить("НоваяКолонка", Новый ОписаниеТипов("Число"));
ТЗ.Колонки.НоваяКолонка = Стр.Свойство;
КонецЦикла;
В приведенном алгоритме допущены три критические ошибки:
ТЗ.Колонки.Добавить() на каждой итерации пытается создать дублирующуюся колонку, что приводит к ошибке или неэффективной работе. Описание структуры должно выполняться один раз до входа в цикл.ТЗ.Колонки содержит объекты метаописания колонок (тип КолонкаТаблицыЗначений). Попытка присвоить значение в ТЗ.Колонки.НоваяКолонка вызывает системную ошибку «Поле объекта недоступно для записи», так как колонка не хранит данные конкретных строк. Запись должна производиться непосредственно в поле текущей строки: Стр.НоваяКолонка.Стр.НоваяКолонка = Стр.Свойство передает строковое значение в колонку, что нивелирует типизацию и не позволяет корректно отсортировать строки по числовому значению.Разберем правильную последовательность действий: сначала добавляем типизированную колонку в коллекцию, затем в цикле обходим строки таблицы, преобразуем строковые данные в число с помощью функции Число(), а после завершения цикла вызываем метод сортировки Сортировать().
Посмотрим на пример правильной реализации:
ВыгрузкаТовары = Запрос.Выполнить();
ТЗ = ВыгрузкаТовары.Выгрузить();
// 1. Добавляем колонку один раз до начала цикла
Квалификатор = Новый КвалификаторыЧисла(15, 2);
ТЗ.Колонки.Добавить("ЧисловоеЗначение", Новый ОписаниеТипов("Число", Квалификатор));
// 2. Обходим строки и заполняем данные
Для Каждого Стр Из ТЗ Цикл
ОчищеннаяСтрока = СокрЛП(Стр.Свойство);
ОчищеннаяСтрока = СтрЗаменить(ОчищеннаяСтрока, Символы.НПП, "");
ОчищеннаяСтрока = СтрЗаменить(ОчищеннаяСтрока, " ", "");
Попытка
Стр.ЧисловоеЗначение = Число(ОчищеннаяСтрока);
Исключение
Стр.ЧисловоеЗначение = 0;
КонецПопытки;
КонецЦикла;
// 3. Выполняем сортировку таблицы значений
ТЗ.Сортировать("ЧисловоеЗначение Возр");
Обратите внимание на использование конструкции Попытка ... Исключение. Встроенная функция Число() вызывает критическую ошибку, если строка содержит нечисловые символы, неразрывные пробелы (Символы.НПП) или пробелы-разделители групп разрядов. Предварительная очистка строки защищает алгоритм от аварийного завершения.
Если создание дополнительной колонки нежелательно, отсортировать строки можно без явного приведения типов к числу. Для этого строковые представления чисел выравнивают по длине с помощью добавления ведущих нулей слева.
Выясним причину, почему обычное добавление нулей не дает результата: если добавлять нули в конец строки или не выравнивать общую длину, лексикографический порядок не совпадет с числовым. Чтобы сортировка сработала правильно, все строки должны иметь строго одинаковую фиксированную длину.
Посмотрим, как реализовать выравнивание ведущими нулями:
Для Каждого Стр Из ТЗ Цикл
// Дополняем строку нулями слева до фиксированной длины (например, 10 знаков)
ИсходноеЗначение = СокрЛП(Стр.Свойство);
Стр.Свойство = Прав("0000000000" + ИсходноеЗначение, 10);
КонецЦикла;
// Теперь строки вида "0000000001", "0000000022", "0000000444" сортируются корректно
ТЗ.Сортировать("Свойство Возр");
Данный способ подходит для целых неотрицательных чисел фиксированной разрядности, однако создание отдельной типизированной числовой колонки является более универсальным и надежным решением.