Как правильно найти максимальный строковый номер в запросе 1С, если «99» оказывается больше «100»?

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

В практике разработки на платформе 1С программисты часто сталкиваются с ситуацией, когда при попытке выбрать максимальное значение из списка строковых номеров (например, номеров документов вида 100/А, 99/А, 3/Б) результат оказывается непредсказуемым с точки зрения математики. Вместо ожидаемого 100/А система возвращает 99/А. Давайте разберем, почему это происходит, как устроена логика сравнения строк в базах данных и какие стратегии решения этой задачи существуют.

Разберем причину: Лексикографическое сравнение строк

Первое, что нам необходимо усвоить: строки в 1С (и в SQL в целом) сравниваются не как числа, а посимвольно, слева направо. Проанализируем ситуацию глазами программы. Сравнивая две строки "100/А" и "99/А", система берет первые символы:

  1. Первый символ первой строки — "1".
  2. Первый символ второй строки — "9".
  3. Поскольку код символа "9" больше кода символа "1", программа делает однозначный вывод: вторая строка больше первой.

Дальнейшие символы (нолики в числе 100 или дробная часть) даже не рассматриваются, так как результат уже определен на первом шаге. Это называется лексикографическим порядком. Именно поэтому короткая строка может считаться «больше» длинной, если её начальные символы имеют больший код в таблице символов.

Важный момент: В 1С при сравнении строк в запросах СУБД может виртуально дополнять строки пробелами до равной длины, но это не меняет базового правила: сравнение идет по кодам символов от начала к концу. Поэтому "2" всегда будет больше, чем "111".

Решение №1: Использование лидирующих нулей (Padding)

Самый простой и эффективный способ заставить строковые номера сортироваться правильно — привести их к единому формату с фиксированной длиной. Для этого используются так называемые лидирующие нули. Если мы преобразуем наши номера к виду "00099/А" и "00100/А", сравнение пойдет по-другому:

  1. Первые символы: "0" и "0" (равны).
  2. Вторые символы: "0" и "0" (равны).
  3. Третьи символы: "0" и "1". На этом этапе система поймет, что "00100" больше.

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


// Пример дополнения номера до 10 символов
ДлинаНомера = 10;
Префикс = "А/";
ЧисловаяЧасть = "99";
ДополненныйНомер = Префикс + Прав("0000000000" + ЧисловаяЧасть, ДлинаНомера);

В запросе реализовать такое дополнение гораздо сложнее, так как функция Формат() там недоступна. Поэтому оптимальная стратегия — хранить в базе номера уже в правильном, дополненном формате.

Решение №2: Создание дополнительного числового реквизита

Если специфика вашего учета требует, чтобы пользователь видел номер именно в формате 99/А, а программисту нужно быстро находить максимум в запросе, лучшим решением будет создание скрытого числового реквизита (например, НомерДляСортировки).

Проанализируем этот подход по шагам:

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

Этот метод работает быстрее всего, так как поиск максимума по индексированному числовому полю в SQL выполняется мгновенно, в отличие от сложных манипуляций со строками.

Решение №3: Функции языка запросов (для версии 8.3.20 и выше)

В современных версиях платформы 1С появились расширенные функции работы со строками непосредственно в тексте запроса. Выясним, как их можно применить. Используя функции СТРДЛИНА, СТРНАЙТИ и ПОДСТРОКА, мы можем попытаться выделить значимые части номера.

Если номера имеют простую структуру (только цифры), можно сортировать сначала по длине строки, а затем по самой строке. Посмотрим на логику:


ВЫБРАТЬ
    Документ.Номер КАК Номер
ИЗ
    Документ.Продажи КАК Документ
УПОРЯДОЧИТЬ ПО
    СТРДЛИНА(Документ.Номер),
    Документ.Номер

При такой сортировке номер "100" (длина 3) всегда будет стоять позже, чем "99" (длина 2), что и требуется для корректного поиска максимума. Однако помните, что использование функций обработки строк в предложении УПОРЯДОЧИТЬ ПО или в условиях может замедлить запрос на больших объемах данных, так как СУБД не сможет использовать стандартные индексы.

Решение №4: Сложная манипуляция в запросе (Метод «Разделяй и властвуй»)

В исключительных случаях, когда перенумеровать документы невозможно, а версию платформы нельзя обновить, программисты прибегают к декомпозиции строки. Проанализируем алгоритм, предложенный в обсуждении (сообщение 34):

  1. Разбиваем строку на символы с помощью вспомогательной таблицы чисел.
  2. Определяем позицию разделителя (например, знака /).
  3. Выделяем часть до разделителя и преобразуем её логически (через ВЫБОР КОГДА) в подобие числа или дополняем нулями «на лету».

Рассмотрим фрагмент концепции такого запроса:


ВЫБРАТЬ
    Выборка.Номер,
    ВЫБОР 
        КОГДА Выборка.Номер ПОДОБНО "_/___" ТОГДА "00" + Выборка.Номер
        КОГДА Выборка.Номер ПОДОБНО "__/___" ТОГДА "0" + Выборка.Номер
        ИНАЧЕ Выборка.Номер 
    КОНЕЦ КАК СортируемыйНомер
ИЗ
    ...

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

Выводы и рекомендации

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

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

← На главную