Как правильно отсортировать справочник по коду в запросе 1С, если в нем нет ведущих нулей?

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

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

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

Способ 1. Сортировка по длине строки и значению (универсальный метод)

Проанализируем ситуацию: почему 10 оказывается выше 2? Потому что при сравнении строк первый символ "1" меньше первого символа "2". Самый простой способ заставить запрос сортировать данные корректно, не прибегая к сложным математическим вычислениям, — это сначала отсортировать данные по длине кода, а уже внутри одной длины — по самому значению кода.

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


ВЫБРАТЬ
    Контрагенты.Ссылка КАК Ссылка,
    Контрагенты.Код КАК Код,
    ВЫБОР
        КОГДА ПОДСТРОКА(Контрагенты.Код, 10, 1) <> "" ТОГДА 10
        КОГДА ПОДСТРОКА(Контрагенты.Код, 9, 1) <> "" ТОГДА 9
        КОГДА ПОДСТРОКА(Контрагенты.Код, 8, 1) <> "" ТОГДА 8
        КОГДА ПОДСТРОКА(Контрагенты.Код, 7, 1) <> "" ТОГДА 7
        КОГДА ПОДСТРОКА(Контрагенты.Код, 6, 1) <> "" ТОГДА 6
        КОГДА ПОДСТРОКА(Контрагенты.Код, 5, 1) <> "" ТОГДА 5
        КОГДА ПОДСТРОКА(Контрагенты.Код, 4, 1) <> "" ТОГДА 4
        КОГДА ПОДСТРОКА(Контрагенты.Код, 3, 1) <> "" ТОГДА 3
        КОГДА ПОДСТРОКА(Контрагенты.Код, 2, 1) <> "" ТОГДА 2
        ИНАЧЕ 1
    КОНЕЦ КАК ДлинаКода
ИЗ
    Справочник.Контрагенты КАК Контрагенты
УПОРЯДОЧИТЬ ПО
    ДлинаКода,
    Код

Что мы сделали: мы создали виртуальное поле ДлинаКода. Если в десятой позиции кода есть символ, значит длина минимум 10. Если в десятой пусто, а в девятой есть — длина 9. В блоке УПОРЯДОЧИТЬ ПО мы сначала ставим короткие коды, затем длинные. Внутри групп с одинаковой длиной обычная строковая сортировка сработает идеально (10 будет меньше 20, а 100 — меньше 110).

Способ 2. Дополнение нулями (нормализация в запросе)

Другой подход заключается в том, чтобы «на лету» привести все коды к одной длине, добавив к ним ведущие нули в виртуальном поле. Рассмотрим вариант реализации через конкатенацию строк. Если мы знаем, что максимальная длина кода в справочнике составляет 9 символов, мы можем применить следующую логику:


ВЫБРАТЬ
    Контрагенты.Код КАК ОригинальныйКод,
    ВЫБОР
        КОГДА Контрагенты.Код ПОДОБНО "_" ТОГДА "00" + Контрагенты.Код
        КОГДА Контрагенты.Код ПОДОБНО "__" ТОГДА "0" + Контрагенты.Код
        ИНАЧЕ Контрагенты.Код
    КОНЕЦ КАК КодДляСортировки
ИЗ
    Справочник.Контрагенты КАК Контрагенты
УПОРЯДОЧИТЬ ПО
    КодДляСортировки

Однако этот метод довольно громоздкий, если длина кода большая (например, 11 символов в типовых конфигурациях). Выясним причину, почему это неудобно: придется писать 10 веток КОГДА. Поэтому такой способ лучше использовать только для справочников с короткой длиной кода.

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

Если ваша база работает на современной платформе (версии 8.3.20 и выше), ситуация значительно упрощается. Фирма «1С» расширила язык запросов, добавив в него функции для работы со строками и числами, которые выполняются на стороне СУБД. Теперь мы можем использовать функцию ЧИСЛО или ПРАВО.

Посмотрим на пример использования новых функций:


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

Или, если вы уверены, что в коде только цифры, можно попробовать прямое преобразование (хотя это может замедлить запрос на больших объемах данных):


ВЫБРАТЬ
    Контрагенты.Ссылка
ИЗ
    Справочник.Контрагенты КАК Контрагенты
УПОРЯДОЧИТЬ ПО
    ВЫРАЗИТЬ(Контрагенты.Код КАК ЧИСЛО) // Доступно в последних версиях платформы

Важный нюанс: использование функций преобразования типов в УПОРЯДОЧИТЬ ПО может привести к тому, что СУБД не сможет использовать индексы. Если в справочнике сотни тысяч записей, такой запрос может выполняться медленно.

Способ 4. Решение через Систему компоновки данных (СКД)

Если задача стоит в рамках разработки отчета, проанализируем возможности СКД. В СКД можно создать вычисляемое поле, которое не будет участвовать в основном тексте запроса к БД, но будет рассчитано средствами самой платформы перед выводом.

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

Преимущество этого метода в том, что основной запрос остается «чистым» и быстрым, а преобразованием типов занимается сама 1С при компоновке результата. Это работает даже на старых версиях платформы, так как язык выражений СКД богаче языка запросов.

Способ 5. Глобальное решение — нормализация данных

Разберем ситуацию с точки зрения архитектуры. Если бухгалтеры «перелопатили» коды, это будет создавать проблемы не только в этом конкретном запросе, но и во всех списках, подборах и других отчетах. Программисты рекомендуют не бороться с симптомами, а устранить причину.

Рассмотрим шаги по исправлению данных:

  1. Групповое перекодирование: Воспользуйтесь типовой обработкой «Групповое изменение реквизитов» или напишите простенький скрипт, который добавит ведущие нули ко всем коротким кодам. Например, код 1 превратится в 000000001.
  2. Подписка на событие: Чтобы ситуация не повторилась, создайте подписку на событие ПередЗаписью для справочника Контрагенты. В обработчике проверяйте длину введенного кода и дополняйте его нулями автоматически.
  3. Запрет редактирования: В настройках прав (ролей) или через функциональные опции можно ограничить право пользователя на редактирование кода. В типовых конфигурациях 1С:Бухгалтерия 3.0 это поле обычно закрыто для редактирования по умолчанию, и пользователю нужно специально нажимать «Еще — Разрешить редактирование реквизитов».

Пример кода для нормализации при записи:


Процедура ПриУстановкеНовогоКода(Источник, СтандартнаяОбработка, Префикс)
    // Стандартный механизм 1С сам заботится о нулях, 
    // если пользователь не вмешивается.
КонецПроцедуры

Процедура ПередЗаписью(Источник, Отказ)
    Если Источник.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    // Дополняем код нулями до нужной длины (например, 9)
    Пока СтрДлина(Источник.Код) < 9 Цикл
        Источник.Код = "0" + Источник.Код;
    КонецЦикла;
КонецПроцедуры

Подведем итог

Мы рассмотрели несколько путей решения задачи. Если вам нужно быстрое решение в запросе — используйте сортировку по длине через ПОДСТРОКА. Если вы работаете с отчетом — используйте вычисляемые поля СКД. Но самым профессиональным подходом будет нормализация кодов в базе данных: это один раз решит проблему для всех пользователей и всех будущих отчетов, обеспечив высокую производительность системы.

← На главную