Как передавать параметры в SQL-запрос через ADO в 1С

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

При интеграции 1С с внешними базами данных через ADO (ActiveX Data Objects) программисты часто сталкиваются с проблемой передачи параметров в SQL-запрос. Начинающие разработчики нередко используют простую подстановку строк (конкатенацию), что приводит к ошибкам типизации и создает серьезные уязвимости, такие как SQL-инъекции. В этой статье мы подробно разберем, как правильно использовать объект ADODB.Command для безопасной и эффективной передачи параметров.

Почему нельзя просто заменять текст в запросе

Рассмотрим ситуацию: вам нужно выбрать данные из SQL Server по определенному номеру документа. Самый очевидный, но неправильный путь — использование функции СтрЗаменить или сложение строк. Проанализируем риски:

  1. Безопасность. Если значение параметра приходит из текстового поля ввода, злоумышленник может ввести специальную последовательность символов (например, 1; DROP TABLE Users), что приведет к выполнению произвольного кода на сервере.
  2. Типизация. Форматы дат и чисел в 1С и SQL Server различаются. При передаче даты строкой легко ошибиться в формате (ГГГГММДД или ДД-ММ-ГГГГ), что вызовет ошибку выполнения.
  3. Производительность. SQL Server кеширует планы выполнения запросов. Если текст запроса постоянно меняется (из-за вставленных значений), сервер будет каждый раз компилировать запрос заново. Параметризованные запросы позволяют использовать один и тот же план выполнения многократно.

Использование объекта ADODB.Command

Для правильной работы с параметрами нам потребуется объект ADODB.Command. Разберем по шагам процесс настройки соединения и подготовки запроса.

Сначала создадим объекты соединения и команды:


СоединениеSQL = Новый COMОбъект("ADODB.Connection");
КомандаSQL    = Новый COMОбъект("ADODB.Command");

СоединениеSQL.ConnectionString = "Provider=MSOLEDBSQL;Data Source=ServerName;Initial Catalog=DBName;Integrated Security=SSPI;";
СоединениеSQL.Open();

КомандаSQL.ActiveConnection = СоединениеSQL;

Способ 1: Позиционные параметры (символ "?")

Это универсальный способ, который поддерживается практически всеми провайдерами OLE DB. В тексте запроса вместо конкретных значений мы ставим знак вопроса. Посмотрим на пример:


ТекстЗапроса = "SELECT * FROM dbo.Orders WHERE OrderDate > ? AND TotalAmount > ?";
КомандаSQL.CommandText = ТекстЗапроса;
КомандаSQL.CommandType = 1; // adCmdText

Теперь нам нужно создать параметры и добавить их в коллекцию Parameters. Важно помнить, что при использовании знака вопроса параметры должны добавляться строго в том порядке, в котором они встречаются в тексте запроса.

Разберем метод CreateParameter. Он принимает следующие аргументы:

  1. Имя (строка) — в данном случае может быть любым.
  2. Тип (число) — код типа данных (например, 135 для даты, 3 для целого числа).
  3. Направление (число) — обычно 1 (входной параметр).
  4. Размер (число) — максимальная длина для строковых типов.
  5. Значение — само значение из 1С.

// Добавляем первый параметр (Дата)
ПараметрДата = КомандаSQL.CreateParameter("p_date", 135, 1, , ДатаНачала);
КомандаSQL.Parameters.Append(ПараметрДата);

// Добавляем второй параметр (Сумма)
ПараметрСумма = КомандаSQL.CreateParameter("p_amount", 3, 1, , 1000);
КомандаSQL.Parameters.Append(ПараметрСумма);

ВыборкаSQL = КомандаSQL.Execute();

Способ 2: Именованные параметры (символ "@")

Если вы работаете с Microsoft SQL Server, удобнее использовать именованные параметры. Это делает код более читаемым и позволяет не зависеть от порядка добавления параметров в коллекцию. Чтобы этот механизм заработал, необходимо установить свойство NamedParameters в значение Истина.

Рассмотрим пример реализации:


КомандаSQL.CommandText = "SELECT FIO FROM Personal WHERE TabNumber = @TabNum AND Status = @Status";
КомандаSQL.NamedParameters = Истина;

// Создаем и сразу добавляем параметры
КомандаSQL.Parameters.Append(КомандаSQL.CreateParameter("@TabNum", 3, 1, , 12345));
КомандаSQL.Parameters.Append(КомандаSQL.CreateParameter("@Status", 202, 1, 50, "Active"));

ВыборкаSQL = КомандаSQL.Execute();

Таблица соответствия типов данных

Для корректной работы метода CreateParameter необходимо правильно указывать числовые коды типов (DataTypeEnum). Проанализируем наиболее часто используемые:

Важный нюанс при работе со строками: если вы используете типы adVarChar (200) или adVarWChar (202), обязательно указывайте четвертый параметр — размер строки. Если передать 0 или оставить пустым, ADO может обрезать строку до первого символа или выдать ошибку.

Обработка пустых дат и значений NULL

Выясним причину частых ошибок при передаче дат. В 1С "пустая" дата — это 01.01.0001. Однако SQL Server (тип datetime) поддерживает даты только начиная с 1753 года. Если попытаться передать пустую дату напрямую, запрос упадет с ошибкой.

Правильным подходом будет передача значения NULL, если дата не заполнена:


ЗначениеДляПередачи = ?(ДатаДокумента = '00010101', Null, ДатаДокумента);
Параметр = КомандаSQL.CreateParameter("@Date", 135, 1, , ЗначениеДляПередачи);
КомандаSQL.Parameters.Append(Параметр);

Вызов хранимых процедур

Если ваша логика вынесена на сторону SQL сервера в виде хранимой процедуры, работа с параметрами становится еще проще. Установим тип команды CommandType = 4 (adStoredProc):


КомандаSQL.CommandText = "sp_GetEmployeeData";
КомандаSQL.CommandType = 4;

// Имена параметров должны строго совпадать с именами в процедуре
КомандаSQL.Parameters.Append(КомандаSQL.CreateParameter("@EmployeeID", 3, 1, , 77));
ВыборкаSQL = КомандаSQL.Execute();

В этом режиме ADO понимает, что CommandText — это не SQL-запрос, а имя процедуры, и корректно сопоставляет коллекцию параметров с аргументами на сервере.

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

Для удобства работы в 1С мы рекомендуем создать вспомогательную функцию-обертку, которая будет автоматически определять тип параметра 1С и конвертировать его в код ADO. Это избавит вас от необходимости помнить числовые константы и сделает код чище.

Проанализируем основные выводы нашей работы:

  1. Всегда используйте ADODB.Command вместо прямого выполнения текста через Connection.Execute, если в запросе есть переменные.
  2. Для кириллицы всегда выбирайте тип adVarWChar (202).
  3. Устанавливайте NamedParameters = Истина для работы с именованными параметрами в MS SQL Server.
  4. Следите за соответствием типов и не забывайте про ограничения минимальных дат в SQL.

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

← На главную