Как в 1С 7.7 выбрать номенклатуру с определенным префиксом кода через запрос?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

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

Разберем типичную ситуацию: требуется выбрать все элементы с префиксом «ХР», за которым следуют только цифры (например, ХР00001, ХР00002). При простом условии проверки левой части строки в выборку неизбежно попадают элементы с кодами ХРИн0531, ХРПМ0002 и подобные, что нарушает логику поиска. Проанализируем причины этой проблемы и подробно рассмотрим надежные способы её решения.

Почему возникают ошибки при отборе по префиксу в запросах 1С 7.7

Штатный механизм запросов 1С 7.7 имеет ряд особенностей и ограничений, которые необходимо учитывать:

  1. Недостаточная точность строковых условий: применение конструкции вида Условие(Лев(КодНом, ДлинаПрефикса) = Префикс) отбирает любые строки, начинающиеся с указанных букв, независимо от того, какие символы (буквы или цифры) идут следом.
  2. Ошибка преобразования типов: попытка проверить цифровую часть с помощью конструкции Число(Сред(...)) приведет к аварийному завершению программы с системной ошибкой: «Преобразование значения к типу Число не может быть выполнено», если в строке окажутся нечисловые символы.
  3. Отсутствие встроенных регулярных выражений: штатный язык запросов 1С 7.7 не поддерживает операторы расширенного поиска по маске или диапазонам символов.

Рассмотрим рабочие способы правильной выборки данных.

Способ 1. Использование экспортной функции Глобального модуля в секции «Условие»

Платформа 1С 7.7 позволяет вызывать в секции Условие(...) штатного запроса любые экспортные функции, определенные в Глобальном модуле конфигурации. Это дает возможность реализовать сколь угодно сложную логику валидации кода.

Разберем реализацию функции проверки. В Глобальном модуле объявляем экспортную функцию, которая проверяет совпадение префикса и строго числовой состав оставшейся части кода:


Функция глПроверитьКод(Знач Код, Знач Префикс) Экспорт
    Код = СокрЛП(Код);
    Префикс = СокрЛП(Префикс);
    ДлинаПрефикса = СтрДлина(Префикс);
    ДлинаКода = СтрДлина(Код);
    
    // Проверяем минимальную длину и начальный префикс
    Если ДлинаКода <= ДлинаПрефикса Тогда
        Возврат 0;
    КонецЕсли;
    
    Если ВРег(Лев(Код, ДлинаПрефикса)) <> ВРег(Префикс) Тогда
        Возврат 0;
    КонецЕсли;
    
    // Проверяем, что все последующие символы являются цифрами
    Для Позиция = ДлинаПрефикса + 1 По ДлинаКода Цикл
        Символ = Сред(Код, Позиция, 1);
        КодСимвола = КодСимв(Символ);
        // Коды ASCII для цифр от '0' (48) до '9' (57)
        Если (КодСимвола < 48) Или (КодСимвола > 57) Тогда
            Возврат 0;
        КонецЕсли;
    КонецЦикла;
    
    Возврат 1;
КонецФункции

Теперь построим запрос в локальном модуле, вызывая функцию в условии:


Функция ВыбратьНоменклатуруПоПрефиксу(Префикс)
    Перем Запрос, ТекстЗапроса;
    
    Запрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = "
    |БезИтогов;
    |Номенклатура = Справочник.Номенклатура.ТекущийЭлемент;
    |КодНом = Справочник.Номенклатура.Код;
    |Группировка Номенклатура Без Групп;
    |Условие(глПроверитьКод(КодНом, Префикс) = 1);
    |";
    
    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
        Возврат 0;
    КонецЕсли;
    
    Пока Запрос.Группировка(1) = 1 Цикл
        Сообщить("Найден элемент: " + Запрос.Номенклатура + ", Код: " + Запрос.КодНом);
    КонецЦикла;
КонецФункции

Способ 2. Предварительный отбор запросом и фильтрация при обходе группировок

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


Функция ВыбратьКодыСФильтрациейПриОбходе(Префикс)
    Перем Запрос, ТекстЗапроса;
    
    Префикс = СокрЛП(Префикс);
    ДлинаПрефикса = СтрДлина(Префикс);
    
    Запрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = "
    |БезИтогов;
    |Ном = Справочник.Номенклатура.ТекущийЭлемент;
    |КодНом = Справочник.Номенклатура.Код;
    |Группировка Ном Без Групп;
    |Условие(Лев(КодНом, " + ДлинаПрефикса + ") = Префикс);
    |";
    
    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
        Возврат 0;
    КонецЕсли;
    
    Пока Запрос.Группировка(1) = 1 Цикл
        КодЭлемента = СокрЛП(Запрос.КодНом);
        ХвостКода = Сред(КодЭлемента, ДлинаПрефикса + 1);
        
        // Проверяем корректность числовой части
        ЭтоЧисло = 1;
        Если СтрДлина(ХвостКода) = 0 Тогда
            ЭтоЧисло = 0;
        Иначе
            Для Поз = 1 По СтрДлина(ХвостКода) Цикл
                СимвКод = КодСимв(Сред(ХвостКода, Поз, 1));
                Если (СимвКод < 48) Или (СимвКод > 57) Тогда
                    ЭтоЧисло = 0;
                    Прервать;
                КонецЕсли;
            КонецЦикла;
        КонецЕсли;
        
        Если ЭтоЧисло = 1 Тогда
            // Обрабатываем подходящий элемент
            Сообщить("Элемент: " + Запрос.Ном + " (" + КодЭлемента + ")");
        КонецЕсли;
    КонецЦикла;
КонецФункции

Способ 3. Штатная автонумерация без использования запроса

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

Посмотрим, как это работает на практике:


Спр = СоздатьОбъект("Справочник.Номенклатура");
Спр.Новый();
// Платформа автоматически найдет максимальный код с префиксом "ХР" 
// и присвоит объекту следующий свободный код с сохранением разрядности
Спр.УстановитьНовыйКод("ХР");
Сообщить("Сгенерирован новый код: " + Спр.Код);

Способ 4. Выборка через объект справочника с сортировкой по коду

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


Спр = СоздатьОбъект("Справочник.Номенклатура");
// Включаем упорядочивание по коду
Спр.ПорядокКодов();
Спр.ВыбратьЭлементы();

Пока Спр.ПолучитьЭлемент() = 1 Цикл
    ТекущийКод = СокрЛП(Спр.Код);
    // Так как элементы упорядочены по алфавиту, отслеживаем нужный интервал кодов
    Если Лев(ТекущийКод, СтрДлина(Префикс)) = Префикс Тогда
        // Дополнительно проверяем состав символов
        Сообщить("Найден код: " + ТекущийКод);
    КонецЕсли;
КонецЦикла;

Таким образом, для строгого отбора кодов с префиксом в 1С 7.7 оптимально использовать экспортную функцию Глобального модуля внутри запроса либо выполнять пост-фильтрацию при обходе результатов, а для задач автонумерации применять встроенный метод УстановитьНовыйКод().

← На главную