Работа с базой данных в платформе 1С:Предприятие невозможна без грамотного использования языка запросов. Однако статические запросы, содержащие жестко прописанные значения, в реальной разработке встречаются крайне редко. Гораздо чаще возникает необходимость динамически изменять условия выборки в зависимости от действий пользователя или логики программы. Именно здесь на сцену выходят параметры запроса, позволяющие передавать значения из кода 1С непосредственно в тело запроса.
Правильная установка параметров — это фундамент не только для корректной работы отчетов, но и для производительности системы. Когда вы передаете переменные через механизм параметров, сервер базы данных (например, MS SQL Server или PostgreSQL) может кэшировать план выполнения запроса, что существенно ускоряет работу при многократном вызове с разными данными. В то же время, неправильное использование типов данных или игнорирование пустых значений может привести к ошибкам выполнения или получению неверных результатов.
В данной статье мы подробно разберем механизмы объявления параметров в тексте запроса, способы их заполнения в коде на встроенном языке, а также специфические нюансы работы с коллекциями значений и составными типами. Вы узнаете, как избежать распространенных ошибок и сделать ваш код более читаемым и поддерживаемым.
Синтаксис объявления параметров в тексте запроса
Любой параметр в тексте запроса 1С начинается со специального символа @, за которым следует имя переменной. Имя параметра должно состоять из латинских букв, цифр и символа подчеркивания, при этом оно не должно начинаться с цифры. Важно понимать, что имена параметров чувствительны к регистру только в том случае, если это явно не настроено иначе в свойствах базы данных, но стандартом де-факто в сообществе 1С считается использование имен с большой буквы или в стиле CamelCase для лучшей читаемости.
Параметры могут использоваться в различных частях запроса: в условиях отбора (ГДЕ), в списках полей (хотя это встречается реже и имеет ограничения), а также в конструкциях ЕСТЬ NULL. При объявлении запроса в коде разработчик просто пишет текст запроса как строковую константу, указывая места для подстановки значений.
Рассмотрим базовый пример структуры запроса, где мы планируем отфильтровать документы по конкретному контрагенту и периоду:
ВЫБРАТЬ
РеализацияТоваровУслуг.Ссылка КАК Ссылка,
РеализацияТоваровУслуг.Дата КАК Дата,
РеализацияТоваровУслуг.Контрагент КАК Контрагент
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
РеализацияТоваровУслуг.Контрагент = @Контрагент
И РеализацияТоваровУслуг.Дата МЕЖДУ @ДатаНач И @ДатаКон
В данном примере @Контрагент, @ДатаНач и @ДатаКон являются плейсхолдерами. Сама по себе эта строка кода не выполняет запрос, она лишь описывает его структуру. Платформа 1С при компиляции модуля анализирует текст запроса и понимает, какие внешние данные потребуются для его исполнения. Если вы забудете передать значение хотя бы одного из объявленных параметров при выполнении, система выдаст ошибку выполнения.
⚠️ Внимание: Не используйте зарезервированные слова платформы или имена системных таблиц в качестве имен параметров. Хотя технически это может сработать, такая практика делает код крайне запутанным и может вызвать конфликты при обновлении конфигурации или платформы.
Создание объекта запроса и передача значений
После того как текст запроса сформирован, необходимо создать объект типа Запрос и связать его с этим текстом. Ключевым этапом является установка значений параметров через метод УстановитьПараметр. Этот метод принимает два аргумента: имя параметра (строка) и само значение, которое может быть любого типа, поддерживаемого платформой.
Одной из главных особенностей механизма параметров в 1С является автоматическое приведение типов. Если в базе данных поле имеет тип Число, а вы передаете в параметр строковое представление числа, платформа 1С постарается преобразовать его корректно перед отправкой на сервер СУБД. Однако полагаться на это полностью не стоит: явное соблюдение типов данных — признак качественного кода.
Ниже приведен пример кода на встроенном языке, демонстрирующий процесс инициализации и выполнения запроса:
ТекстЗапроса = "ВЫБРАТЬ ... ГДЕ Код = @КодЭлем";
Запрос = Новый Запрос(ТекстЗапроса);
// Установка скалярного значения
Запрос.УстановитьПараметр("КодЭлем", 12345);
// Выполнение и получение результата
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Особое внимание следует уделить ситуации, когда параметр может принимать неопределенное значение (NULL). В 1С для этого существует специальное значение Неопределено. Если вы передадите Неопределено в параметр, в SQL-запрос уйдет именно NULL. Это критически важно для организации гибких отчетов, где пользователь может оставить некоторые поля фильтра пустыми.
Если вы передаете в параметр дату, всегда обнуляйте время, если вам важна только дата. Используйте функцию НачалоДня(Дата) для избежания ошибок при сравнении с полями, хранящими только дату без времени.
Работа с коллекциями значений и оператором В
Часто возникает задача отобрать данные не по одному значению, а по списку. Например, нужно вывести товары определенных номенклатурных групп или документы нескольких конкретных контрагентов. В языке SQL для этого используется оператор IN (в 1С — В). В 1С:Предприятие передача списка значений в параметр реализована через объект СписокЗначений или таблицу значений.
Когда вы передаете коллекцию в параметр запроса, платформа автоматически разворачивает её в соответствующий SQL-конструкт. Это гораздо эффективнее и безопаснее, чем ручная конкатенация строк через запятую, которая к тому же подвержена риску SQL-инъекций (хотя в 1С этот риск минимизирован самим механизмом запросов).
Алгоритм работы со списком значений выглядит следующим образом:
- 📦 Создается новый объект
СписокЗначений. - ➕ В список добавляются необходимые элементы через метод
Добавить. - ⚙️ Список передается в метод
УстановитьПараметркак единое целое. - 🚀 В тексте запроса используется конструкция
Поле В (&Параметр).
Важно отметить, что тип данных внутри списка значений должен быть совместим с типом поля в базе данных, по которому идет отбор. Если поле является ссылкой на справочник, то в список значений нужно добавлять именно ссылки, а не строковые представления имен элементов.
СписокКонтрагентов = Новый СписокЗначений;
СписокКонтрагентов.Добавить(Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка"));
СписокКонтрагентов.Добавить(Справочники.Контрагенты.НайтиПоНаименованию("ИП Иванов"));
Запрос.УстановитьПараметр("СписокКонтрагентов", СписокКонтрагентов);
Что будет если передать пустой список?
Если передать в параметр пустой СписокЗначений, то условие "Поле В (&Параметр)" вернет ложь для всех записей. В результате выборка будет пустой. Это логичное поведение, но о нем нужно помнить при программировании логики "показать все, если фильтр пуст".
Особенности работы с составными типами и ссылками
В конфигурациях 1С широко используются составные типы данных. Поле в базе данных может хранить ссылку на любой из нескольких справочников (например, "ВидыНоменклатуры" или "Номенклатура"). При установке параметров в запросе для таких полей необходимо учитывать эту специфику. Если вы передаете в параметр значение, тип которого не входит в составной тип поля, запрос может завершиться ошибкой или вернуть пустой результат.
Кроме того, при работе со ссылками часто возникает необходимость сравнивать не саму ссылку, а её владельца или конкретный вид. В таких случаях в запросе используются точечные идентификаторы полей ссылки, например @Параметр.Владелец. Однако, если параметр сам является ссылкой, то прямое сравнение Поле = @Параметр является наиболее производительным вариантом, так как использует индексы базы данных.
Рассмотрим таблицу, иллюстрирующую совместимость типов параметров и полей:
| Тип поля в БД | Допустимый тип параметра | Особенности передачи |
|---|---|---|
| СправочникСсылка.Номенклатура | СправочникСсылка.Номенклатура | Прямая передача ссылки |
| Число(15, 2) | Число | Автоматическое округление не происходит, нужна точность |
| Дата (время = 0) | Дата | Рекомендуется обнулять время функцией НачалоДня() |
| Булево | Булево | Строго Истина или Ложь, Неопределено недопустимо |
При передаче составных типов в параметрах-коллекциях (СписокЗначений) каждый элемент списка может иметь свой тип, но все они должны быть совместимы с целевым полем выборки. Платформа 1С автоматически генерирует сложный SQL-код для обработки таких ситуаций, что избавляет разработчика от ручного написания условий OR.
Всегда проверяйте тип значения перед установкой в параметр, особенно если данные приходят из внешних источников или форм ввода, где пользователь мог выбрать неверный тип.
Динамическое формирование условий и пустые параметры
Одна из самых частых задач при разработке отчетов — создание универсальных форм отбора, где пользователь может заполнить лишь часть полей. Реализация логики "если параметр заполнен, то фильтруем, иначе игнорируем условие" требует аккуратного подхода. Простое использование конструкции ИЛИ @Параметр ЕСТЬ NULL не всегда эффективно с точки зрения производительности, так как может препятствовать использованию индексов.
Более грамотным подходом является динамическое формирование текста запроса или использование специальных приемов с булевыми флагами. Однако, если речь идет о небольших объемах данных, можно использовать конструкцию, проверяющую заполненность параметра непосредственно в условии ГДЕ.
Пример реализации гибкого отбора:
ТекстЗапроса = "ВЫБРАТЬ ...
ГДЕ
(Контрагент = @Контрагент ИЛИ @Контрагент ЕСТЬ NULL)
И (Дата >= @ДатаНач ИЛИ @ДатаНач ЕСТЬ NULL)";
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("Контрагент", ВыбранныйКонтрагент); // Может быть Неопределено
Запрос.УстановитьПараметр("ДатаНач", ДатаНачПериода); // Может быть Неопределено
В этом коде, если переменная ВыбранныйКонтрагент равна Неопределено, то в запрос уйдет NULL. Условие @Контрагент ЕСТЬ NULL станет истиной, и фильтрация по контрагенту фактически отключится. Это позволяет использовать один и тот же текст запроса для различных сценариев работы отчета.
Оптимизация и типичные ошибки при параметризации
Несмотря на мощь механизма параметров, существуют типичные ошибки, которые совершают разработчики, особенно новички. Одной из них является попытка передать в параметр сложные объекты, которые не могут быть сериализованы для передачи на сервер СУБД. Например, нельзя напрямую передать объект формы или динамический список в параметр запроса без предварительной обработки.
Также стоит помнить о лимитах длины запроса и количестве параметров. Хотя в 1С эти лимиты достаточно высоки, при генерации отчетов с сотнями параметров (например, отбор по каждому дню года отдельно) можно столкнуться с ограничениями драйвера базы данных. В таких случаях рекомендуется использовать временные таблицы для передачи больших объемов данных для отбора.
Еще один важный аспект — это производительность. Использование функций от параметров внутри условия ГДЕ (например, ГОД(Дата) = ГОД(@Дата)) почти всегда приводит к полному сканированию таблицы (Table Scan), что убивает производительность на больших базах. Старайтесь сравнивать поля с параметрами напрямую.
- ❌ Избегайте оборачивания полей таблицы в функции в условиях отбора.
- ✅ Используйте диапазон дат (
МЕЖДУ) вместо функций выделения года или месяца. - ⚡ Проверяйте план выполнения запроса через консоль запросов при подозрении на тормоза.
⚠️ Внимание: Интерфейс и возможности консоли запросов могут отличаться в разных версиях платформы 1С. Всегда сверяйте доступные инструменты анализа производительности в актуальной документации для вашей версии 1С:Предприятие.
Часто задаваемые вопросы (FAQ)
Можно ли передать в параметр запроса целую таблицу значений?
Да, это возможно. Вы можете создать объект ТаблицаЗначений, заполнить его колонки и строки, а затем передать эту таблицу в параметр. В запросе к такой таблице можно обращаться как к виртуальной таблице, используя конструкцию ИЗ &ПараметрТаблица. Это мощный инструмент для сложных вычислений без создания временных таблиц в базе данных.
Что делать, если имя параметра совпадает с именем поля в таблице?
Конфликта не возникнет, так как параметры всегда начинаются с символа @, а поля в запросе указываются без него (или с псевдонимом таблицы). Платформа 1С четко разграничивает пространства имен параметров и полей выборки. Однако для читаемости кода лучше избегать одинаковых имен.
Как передать в запрос значение перечисления (Enum)?
Значения перечислений передаются как обычные значения. Вы можете написать Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыЗаказов.ВРаботе). В запросе это значение будет корректно обработано, так как перечисления в 1С имеют внутренние числовые или строковые представления, понятные платформе.
Влияет ли порядок установки параметров на выполнение запроса?
Нет, порядок вызова метода УстановитьПараметр не имеет значения. Главное, чтобы все параметры, объявленные в тексте запроса через символ @, были установлены до вызова метода Выполнить. Имя параметра в методе установки должно точно совпадать с именем в тексте запроса.