При работе с платформой 1С часто возникает задача выбрать данные из справочника в определенном диапазоне кодов. На первый взгляд задача кажется тривиальной, но на практике программисты сталкиваются с тем, что код в 1С чаще всего является строковым типом данных. Это накладывает определенные ограничения на использование математических операторов и требует понимания того, как СУБД сравнивает строки. Рассмотрим подробно способы решения этой задачи, разберем возможные ошибки и методы оптимизации запросов.
Прежде чем приступать к написанию запроса, нам необходимо разобраться, как 1С сравнивает коды. Поскольку Код в справочнике Номенклатура обычно имеет тип Строка, сравнение происходит посимвольно слева направо (лексикографически).
Проанализируем ситуацию: если мы попытаемся сравнить строки "10" и "2", то строка "10" будет считаться меньше строки "2", так как первый символ "1" меньше символа "2". Именно поэтому в типовых конфигурациях коды дополняются ведущими нулями (например, "00-00000015"). Это гарантирует, что при одинаковой длине строк их лексикографический порядок будет совпадать с числовым.
Если коды в вашей базе данных имеют фиксированную длину и дополнены нулями, оператор МЕЖДУ (или BETWEEN в SQL) будет работать корректно даже для строковых типов. Выясним, как правильно составить такой запрос.
Рассмотрим пример запроса, который должен выбрать номенклатуру с кодами от 0 до 90, учитывая формат "00-000000XX":
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка,
Номенклатура.Код КАК Код,
Номенклатура.Наименование КАК Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Код МЕЖДУ &Мин И &Макс
Важный нюанс: Чтобы этот запрос отработал правильно, в параметры &Мин и &Макс нужно передавать не числа 0 и 90, а полностью сформированные строки, соответствующие формату кода в базе. Например:
&Мин = "00-00000000"&Макс = "00-00000090"Если вы столкнулись с ошибкой "Индекс находится за границами массива" при заполнении параметров в консоли запросов, как это случилось у автора темы, проанализируем причину. Скорее всего, это ошибка самой консоли (инструментария), а не языка запросов. Попробуйте воспользоваться другой версией консоли запросов или выполнить этот код непосредственно в модуле обработки.
Если диапазон кодов невелик или коды имеют сложную структуру, которую трудно описать простым сравнением "больше-меньше", можно пойти от обратного. Сформируем список всех подходящих кодов заранее в коде 1С и передадим его в запрос.
Разберем этот метод по шагам:
В (&СписокКодов).
// Пример на языке 1С
СписокКодов = Новый Массив;
Для Счетчик = 0 По 90 Цикл
// Формируем строку вида 00-000000XX
ТекКод = "00-" + Формат(Счетчик, "ЧЦ=8; ЧВН=; ЧГ=0");
СписокКодов.Добавить(ТекКод);
КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Код В (&СписокКодов)";
Запрос.УстановитьПараметр("СписокКодов", СписокКодов);
Этот способ гарантирует точность выборки, но может негативно сказаться на производительности, если в списке окажутся тысячи значений.
Иногда требуется отобрать данные, когда мы не знаем точного количества ведущих нулей или префиксов. В этом случае программисты прибегают к использованию функции ПОДСТРОКА и конструкции ВЫБОР. Посмотрим на пример "извращенного", но рабочего подхода для удаления ведущих нулей программно внутри запроса:
ВЫБРАТЬ
Номенклатура.Наименование,
ВЫБОР
КОГДА НЕ ПОДСТРОКА(Номенклатура.Код, 1, 1) = "0" ТОГДА ПОДСТРОКА(Номенклатура.Код, 1, 10)
КОГДА НЕ ПОДСТРОКА(Номенклатура.Код, 2, 1) = "0" ТОГДА ПОДСТРОКА(Номенклатура.Код, 2, 9)
// ... и так далее для каждого разряда
ИНАЧЕ ПОДСТРОКА(Номенклатура.Код, 10, 1)
КОНЕЦ КАК КодБезНулей
ИЗ
Справочник.Номенклатура КАК Номенклатура
Внимание! Мы крайне не рекомендуем использовать такие конструкции в реальных задачах. Проанализируем последствия: использование функций обработки строк (ПОДСТРОКА, ВЫБОР) в секции ГДЕ или в вычисляемых полях для условий приводит к тому, что СУБД не сможет использовать индекс по полю Код. Это вызовет полное сканирование таблицы (Full Scan), что приведет к критическому замедлению системы на больших справочниках.
Чтобы ваши запросы работали быстро и корректно, придерживайтесь следующих правил:
Код в 1С индексируется по умолчанию. Не "ломайте" работу индекса, применяя к этому полю функции внутри условия ГДЕ.Число. Заполняйте его в событии ПриЗаписи и индексируйте. Это позволит выполнять математические отборы мгновенно.ВЫРАЗИТЬ не может превратить Строку в Число. Она предназначена для других целей (ограничение длины строки или приведение ссылочных типов).Таким образом, самым эффективным решением для автора вопроса является использование оператора МЕЖДУ с корректно подготовленными строковыми параметрами в правильной консоли запросов.