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

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

В платформе 1С:Предприятие программисты часто сталкиваются с ситуацией, когда стандартная сортировка по номеру документа или договора работает не так, как ожидает пользователь. Например, договор №11 оказывается в списке выше, чем договор №5. Разберем, почему это происходит и как реализовать «человеческую» (естественную) сортировку в ваших отчетах и обработках на примере конфигурации 1С:Комплексная автоматизация 2.

Почему 11 меньше 5: природа строковой сортировки

Прежде чем переходить к коду, проанализируем причину проблемы. В справочнике ДоговорыКонтрагентов реквизит Номер имеет тип Строка. В базах данных строки сравниваются посимвольно (лексикографически), слева направо. При сравнении строк "11" и "5" система сначала сравнивает первый символ: "1" и "5". Поскольку единица меньше пятерки, строка "11" признается меньшей, и дальнейшее сравнение прекращается. Для системы это так же логично, как то, что слово «Абакан» идет раньше слова «Барнаул».

Однако пользователи хотят видеть числовую логику: 2, 4, 11, 12, ГБ1. Рассмотрим несколько способов добиться такого результата в запросах 1С.

Способ 1. Выравнивание строк пробелами в запросе

Это одно из самых изящных и быстрых решений, не требующее изменения структуры конфигурации. Суть метода заключается в том, чтобы «добить» строку пробелами слева до определенной длины. Рассмотрим, как это работает в коде запроса:


ВЫБРАТЬ
    ДоговорыКонтрагентов.Номер КАК НомерПредставление,
    ВЫРАЗИТЬ(ПРАВ("              " + ДоговорыКонтрагентов.Номер, 15) КАК СТРОКА(15)) КАК ПолеДляСортировки
ПОМЕСТИТЬ ВТ_Договоры
ИЗ
    Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
ГДЕ
    ДоговорыКонтрагентов.Контрагент = &Контрагент
;

ВЫБРАТЬ
    ВТ_Договоры.НомерПредставление
ИЗ
    ВТ_Договоры КАК ВТ_Договоры
УПОРЯДОЧИТЬ ПО
    ВТ_Договоры.ПолеДляСортировки

Проанализируем этот алгоритм. Мы берем строку из 15 пробелов и прибавляем к ней наш номер. Если номер был "5", получится " 5". Если был "11", получится " 11". Затем с помощью функции ПРАВ мы отсекаем ровно 15 символов справа. В итоге все номера становятся одной длины, и при сравнении пробел (код которого меньше кода цифры) заставит короткие числа встать в начало списка.

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

Способ 2. Сортировка по длине строки

Если в вашей базе номера договоров содержат только цифры (без буквенных префиксов типа «ГБ»), можно применить упрощенный метод двойной сортировки. Сначала мы упорядочиваем данные по количеству символов в строке, а затем по самой строке.


ВЫБРАТЬ
    ДоговорыКонтрагентов.Номер,
    ДоговорыКонтрагентов.Контрагент
ИЗ
    Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
ГДЕ
    ДоговорыКонтрагентов.Контрагент = &Контрагент
УПОРЯДОЧИТЬ ПО
    ДЛИНАСТРОКИ(ДоговорыКонтрагентов.Номер),
    ДоговорыКонтрагентов.Номер

В этом случае договор с номером "5" (длина 1) гарантированно окажется выше договора "11" (длина 2). Однако этот метод «сломается», если появятся префиксы разной длины, например "А1" и "100".

Способ 3. Использование вспомогательной таблицы префиксов

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


// Создаем таблицу длин и префиксов (нулей или пробелов)
ВЫБРАТЬ 1 КАК ДлинаСтроки, "000" КАК Префикс ПОМЕСТИТЬ ВТ_Префиксы ОБЪЕДИНИТЬ
ВЫБРАТЬ 2, "00" ОБЪЕДИНИТЬ
ВЫБРАТЬ 3, "0" ОБЪЕДИНИТЬ
ВЫБРАТЬ 4, "";

ВЫБРАТЬ
    Договоры.Номер КАК Оригинал,
    ВТ_Префиксы.Префикс + Договоры.Номер КАК ТехническоеПолеСортировки
ИЗ
    Справочник.ДоговорыКонтрагентов КАК Договоры
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Префиксы КАК ВТ_Префиксы
    ПО ДЛИНАСТРОКИ(Договоры.Номер) = ВТ_Префиксы.ДлинаСтроки
УПОРЯДОЧИТЬ ПО
    ТехническоеПолеСортировки

Этот метод позволяет гибко управлять правилами дополнения строк в зависимости от их текущей длины. Мы как бы «нормализуем» данные перед тем, как отдать их механизму сортировки СУБД.

Способ 4. Добавление реквизита в конфигурацию

Если отчеты по договорам строятся часто и на больших объемах данных (десятки тысяч записей), вычисления «на лету» в запросе могут замедлять работу системы. В таком случае рекомендуется внести изменения в структуру метаданных:

  1. Добавим в справочник ДоговорыКонтрагентов новый реквизит НомерДляСортировки (тип Строка, длина совпадает с основным номером).
  2. В модуле объекта справочника в процедуре ПередЗаписью пропишем логику заполнения этого поля. Например, будем дополнять номер ведущими нулями до фиксированной длины.
  3. Установим у этого реквизита свойство Индексировать, чтобы поиск и сортировка выполнялись мгновенно.

Такой подход позволяет пользователю видеть привычный номер "12", в то время как система будет использовать скрытое поле "000000000012" для идеального упорядочивания.

Рекомендации для СКД

Если вы работаете с Системой компоновки данных, задачу можно решить еще проще. Проанализируем возможности Вычисляемых полей. Вы можете создать поле, значением которого будет выражение на языке 1С (а не языке запросов), и использовать функции общих модулей для преобразования номера. В настройках компоновки на закладке «Сортировка» останется лишь указать это вычисляемое поле.

Выясним, какой из методов лучше. Для разовых отчетов идеально подходит Способ 1 (дополнение пробелами через ПРАВ). Для высоконагруженных систем, где важна скорость — Способ 4 (хранение подготовленного значения в базе). Выбор за вами, но теперь ваши отчеты всегда будут выглядеть профессионально и логично для конечного пользователя.

← На главную