При работе с запросами в системе 1С:Предприятие начинающие (а иногда и опытные) разработчики сталкиваются с ситуацией, когда запрос не возвращает ожидаемые данные, хотя значение параметра кажется верным. Типичный пример: поиск по артикулу или коду, где в базе данных хранится строка, а в параметр передается число. Давайте подробно разберем, почему так происходит, как работает механизм типизации в запросах и какие правила необходимо соблюдать для написания эффективного кода.
Рассмотрим ситуацию, описанную в исходном вопросе. У нас есть запрос к справочнику Номенклатура, где мы пытаемся найти элемент по артикулу:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Артикул = &Артикул";
// Вариант 1:
Запрос.УстановитьПараметр("Артикул", 370); // Не находит
// Вариант 2:
Запрос.УстановитьПараметр("Артикул", "370"); // Находит
Разберем, почему так происходит. В обычном встроенном языке 1С (в модулях) платформа часто прощает небрежность с типами. Например, выражение Если "370" = 370 Тогда может быть вычислено в зависимости от контекста, так как встроенный язык поддерживает гибкое приведение типов. Однако в языке запросов 1С действуют совершенно иные правила.
Язык запросов 1С — это строго типизированный механизм, который транслируется в SQL-запросы к системе управления базами данных (СУБД). С точки зрения базы данных, типы Число и Строка являются принципиально разными сущностями, хранящимися в памяти по-разному. Сравнение Строка = Число на уровне SQL либо приведет к ошибке, либо (что чаще в 1С) просто вернет Ложь, так как объекты разных типов априори не равны друг другу.
Проанализируем ключевую техническую особенность: в запросах 1С полностью отсутствует неявное приведение типов (Implicit Casting). Это сделано намеренно по нескольким причинам:
Выясним, как типизация влияет на скорость работы программы. Поле Артикул в справочнике Номенклатура обычно проиндексировано для быстрого поиска. Индекс строится по значениям конкретного типа (в данном случае — по строкам).
Если мы передаем в параметр число 370, а СУБД попытается сравнить его со строковым полем, ей придется либо конвертировать число в строку для каждой записи таблицы, либо конвертировать все артикулы в числа. В обоих случаях использование индекса становится невозможным. Произойдет так называемое сканирование всей таблицы (Full Table Scan), что на больших справочниках приведет к колоссальным задержкам. Именно поэтому золотое правило разработчика гласит: приводите параметр к типу поля, а не поле к типу параметра.
Рассмотрим еще один нюанс, который часто путает разработчиков. В метаданных 1С строковые поля могут иметь фиксированную или переменную длину. Если для артикула установлена фиксированная длина (например, 25 символов), то в базе данных строка "370" на самом деле хранится как "370 " (дополнена пробелами справа).
Когда мы передаем в запрос строковый параметр "370", платформа 1С при трансляции запроса в SQL автоматически учитывает эту особенность и корректно сопоставляет значение с учетом пробелов. Но если передать число 370, механизм сопоставления типов просто не сработает, и поиск завершится неудачей.
Проанализируем ситуацию с артикулами, содержащими нули в начале, например "000370".
370 в строку стандартной функцией Строка(370), мы получим "370"."000370".В этом случае даже явное приведение типа не поможет, если не соблюдена маска кода. Это еще раз доказывает, что разработчик обязан контролировать формат данных во встроенном языке до того, как запрос будет отправлен на выполнение.
Многие полагают, что проблему можно решить прямо внутри запроса с помощью оператора ВЫРАЗИТЬ. Однако давайте разберем ограничения этого оператора в 1С:
ВЫРАЗИТЬ нельзя использовать для преобразования числа в строку или строки в число.ДокументОснование) к конкретному ссылочному типу или ограничение длины строк/точности чисел.Таким образом, единственный верный способ — это подготовка параметра во встроенном языке:
// Правильная подготовка параметра
АртикулДляПоиска = Формат(ЧисловойАртикул, "ЧГ=0"); // Убираем разделители групп
Запрос.УстановитьПараметр("Артикул", АртикулДляПоиска);
Мы выяснили, что строгое соответствие типов в запросах 1С — это не ошибка, а фундаментальная особенность архитектуры, обеспечивающая стабильность и высокую скорость работы системы. Чтобы ваши запросы всегда работали корректно, придерживайтесь следующих правил:
УстановитьПараметр. Используйте функции Строка(), Число() или Формат() для получения точного строкового представления.ГДЕ, так как это негативно сказывается на использовании индексов СУБД.Соблюдение этих простых принципов позволит вам избежать трудноуловимых ошибок и обеспечит оптимальную производительность ваших решений в 1С.