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

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

При работе с платформой 1С часто возникает задача выбрать данные из справочника в определенном диапазоне кодов. На первый взгляд задача кажется тривиальной, но на практике программисты сталкиваются с тем, что код в 1С чаще всего является строковым типом данных. Это накладывает определенные ограничения на использование математических операторов и требует понимания того, как СУБД сравнивает строки. Рассмотрим подробно способы решения этой задачи, разберем возможные ошибки и методы оптимизации запросов.

Особенности строкового сравнения (Лексикографический порядок)

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

Проанализируем ситуацию: если мы попытаемся сравнить строки "10" и "2", то строка "10" будет считаться меньше строки "2", так как первый символ "1" меньше символа "2". Именно поэтому в типовых конфигурациях коды дополняются ведущими нулями (например, "00-00000015"). Это гарантирует, что при одинаковой длине строк их лексикографический порядок будет совпадать с числовым.

Вариант 1. Использование оператора МЕЖДУ

Если коды в вашей базе данных имеют фиксированную длину и дополнены нулями, оператор МЕЖДУ (или BETWEEN в SQL) будет работать корректно даже для строковых типов. Выясним, как правильно составить такой запрос.

Рассмотрим пример запроса, который должен выбрать номенклатуру с кодами от 0 до 90, учитывая формат "00-000000XX":


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка,
    Номенклатура.Код КАК Код,
    Номенклатура.Наименование КАК Наименование
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.Код МЕЖДУ &Мин И &Макс

Важный нюанс: Чтобы этот запрос отработал правильно, в параметры &Мин и &Макс нужно передавать не числа 0 и 90, а полностью сформированные строки, соответствующие формату кода в базе. Например:

Если вы столкнулись с ошибкой "Индекс находится за границами массива" при заполнении параметров в консоли запросов, как это случилось у автора темы, проанализируем причину. Скорее всего, это ошибка самой консоли (инструментария), а не языка запросов. Попробуйте воспользоваться другой версией консоли запросов или выполнить этот код непосредственно в модуле обработки.

Вариант 2. Использование списка допустимых значений

Если диапазон кодов невелик или коды имеют сложную структуру, которую трудно описать простым сравнением "больше-меньше", можно пойти от обратного. Сформируем список всех подходящих кодов заранее в коде 1С и передадим его в запрос.

Разберем этот метод по шагам:

  1. Создадим массив или список значений.
  2. Циклом заполним его строками нужного формата.
  3. Передадим этот массив в параметр запроса с условием В (&СписокКодов).

// Пример на языке 1С
СписокКодов = Новый Массив;
Для Счетчик = 0 По 90 Цикл
    // Формируем строку вида 00-000000XX
    ТекКод = "00-" + Формат(Счетчик, "ЧЦ=8; ЧВН=; ЧГ=0"); 
    СписокКодов.Добавить(ТекКод);
КонецЦикла;

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Номенклатура.Наименование
    |ИЗ
    |	Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |	Номенклатура.Код В (&СписокКодов)";

Запрос.УстановитьПараметр("СписокКодов", СписокКодов);

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

Вариант 3. Динамическая очистка кода от нулей в запросе

Иногда требуется отобрать данные, когда мы не знаем точного количества ведущих нулей или префиксов. В этом случае программисты прибегают к использованию функции ПОДСТРОКА и конструкции ВЫБОР. Посмотрим на пример "извращенного", но рабочего подхода для удаления ведущих нулей программно внутри запроса:


ВЫБРАТЬ
    Номенклатура.Наименование,
    ВЫБОР
        КОГДА НЕ ПОДСТРОКА(Номенклатура.Код, 1, 1) = "0" ТОГДА ПОДСТРОКА(Номенклатура.Код, 1, 10)
        КОГДА НЕ ПОДСТРОКА(Номенклатура.Код, 2, 1) = "0" ТОГДА ПОДСТРОКА(Номенклатура.Код, 2, 9)
        // ... и так далее для каждого разряда
        ИНАЧЕ ПОДСТРОКА(Номенклатура.Код, 10, 1)
    КОНЕЦ КАК КодБезНулей
ИЗ
    Справочник.Номенклатура КАК Номенклатура

Внимание! Мы крайне не рекомендуем использовать такие конструкции в реальных задачах. Проанализируем последствия: использование функций обработки строк (ПОДСТРОКА, ВЫБОР) в секции ГДЕ или в вычисляемых полях для условий приводит к тому, что СУБД не сможет использовать индекс по полю Код. Это вызовет полное сканирование таблицы (Full Scan), что приведет к критическому замедлению системы на больших справочниках.

Рекомендации по оптимизации

Чтобы ваши запросы работали быстро и корректно, придерживайтесь следующих правил:

Таким образом, самым эффективным решением для автора вопроса является использование оператора МЕЖДУ с корректно подготовленными строковыми параметрами в правильной консоли запросов.

← На главную