Почему запрос МАКСИМУМ возвращает неверный номер документа в 1С и как это исправить

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

При разработке собственных конфигураций или доработке типовых решений разработчики часто сталкиваются с ситуацией, когда запрос к базе данных для получения максимального номера документа возвращает некорректный результат. Например, при наличии документов с номерами PKKR8, PKKR9 и PKKR10 функция МАКСИМУМ(Проекты.Номер) вернет значение PKKR9.

Разберем подробно причину такого поведения платформы 1С и проанализируем варианты решения этой проблемы.

Причина проблемы: правила сравнения строк

Проанализируем, как платформа 1С выполняет агрегатную функцию МАКСИМУМ в языке запросов. Реквизит Номер (или Код) по умолчанию имеет тип Строка. При выполнении запроса происходит посимвольное (лексикографическое) сравнение строк слева направо:

  1. Сравниваются первые символы строк. Если они совпадают, переход идет ко вторым символам.
  2. Сравнивается префикс PKKR — у всех документов он одинаковый.
  3. Далее сравнивается следующий символ: у документа PKKR9 пятым символом является "9", а у документа PKKR10 пятым символом является "1".

Так как в таблице символов знак "9" больше знака "1", с точки зрения системы строка "PKKR9" оказывается больше строки "PKKR10". Язык запросов 1С не преобразует строки в числа на лету и не выполняет математическое сравнение.

Способ 1. Использование ведущих нулей в номерах (фиксированная разрядность)

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

Рассмотрим пример: если номера документов хранятся в формате PKKR00000009 и PKKR00000010, то при посимвольном сравнении строка PKKR00000010 будет признана большей, так как символ "1" в 11-м разряде больше символа "0".

Сформировать корректную строку с ведущими нулями на встроенном языке 1С можно с помощью функции Формат():


ЧисловойНомер = 10;
Префикс = "PKKR";
// Форматируем число с заполнением нулями до 8 знаков без группировки
СтрокаНомера = Префикс + Формат(ЧисловойНомер, "ЧЦ=8; ЧВН=; ЧГ=0");
// Результат: "PKKR00000010"

Способ 2. Использование штатного механизма автонумерации платформы

В платформах 1С:Предприятие для справочников и документов предусмотрен встроенный механизм нумерации. Нам нет необходимости писать собственные запросы для поиска максимального номера, если правильно настроены свойства объекта метаданных:

  1. В свойствах документа укажем тип номера — Строка, а также зададим нужную длину (например, 11 символов).
  2. Включим автонумерацию и контроль уникальности.
  3. При создании или записи нового объекта вызываем метод УстановитьНовыйНомер().

Рассмотрим применение метода в модуле объекта документа:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    Если ЭтоНовый() И Не ЗначениеЗаполнено(Номер) Тогда
        // Автоматически находит последний номер с указанным префиксом и увеличивает его на 1
        УстановитьНовыйНомер(Организация.Суффикс);
    КонецЕсли;
КонецПроцедуры

Платформа 1С самостоятельно проанализирует существующие номера в базе, выделит числовую часть с конца строки, учтет ведущие нули и присвоит документу следующий порядковый номер.

Способ 3. Обработка выборки на встроенном языке

Если изменить структуру номеров в существующей базе данных невозможно (например, номера уже записаны без ведущих нулей) и язык запросов не позволяет привести строки к числу, обработку максимума вычисляют на стороне сервера приложения.

Выберем запросом все номера документов с нужным префиксом, после чего в цикле выделим числовую часть и найдем истинный математический максимум:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Проекты.Номер КАК Номер
    |ИЗ
    |	Документ.Проекты КАК Проекты
    |ГДЕ
    |	Проекты.Организация = &Организация";

Запрос.УстановитьПараметр("Организация", Организация);
Выборка = Запрос.Выполнить().Выбрать();

МаксимальныйНомер = 0;
ДлинаПрефикса = СтрДлина(СокрЛП(Организация.Суффикс));

Пока Выборка.Следующий() Цикл
    // Отрезаем префикс и получаем числовую часть
    СтрокаЧисла = Сред(Выборка.Номер, ДлинаПрефикса + 1);
    ЧисловойНомер = Число(СтрокаЧисла);
    
    Если ЧисловойНомер > МаксимальныйНомер Тогда
        МаксимальныйНомер = ЧисловойНомер;
    КонецЕсли;
КонецЦикла;

СледующийНомерЧислом = МаксимальныйНомер + 1;
НовыйНомерДокумента = Организация.Суффикс + Формат(СледующийНомерЧислом, "ЧГ=0");

Рекомендации

Во избежание ошибок при нумерации объектов в 1С рекомендуется:

← На главную