Как правильно вызвать SQL-функцию с параметрами из 1С через ADO

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

При интеграции 1С с внешними базами данных SQL Server через механизм ADO (ActiveX Data Objects) программисты часто сталкиваются с трудностями при вызове пользовательских функций (UDF). Основные проблемы обычно связаны либо с ошибкой Invalid object name, либо с тем, что возвращаемый набор записей (Recordset) кажется пустым или не содержит нужных полей. В этой статье мы подробно разберем, как правильно составить запрос, передать параметры и получить результат.

Анализ проблемы: скалярные и табличные функции

Прежде чем приступать к написанию кода, проанализируем, почему возникают ошибки в разных вариантах написания CommandText. В SQL Server существует два основных типа функций, и синтаксис их вызова в SELECT принципиально различается:

  1. Скалярные функции — возвращают ровно одно значение (число, строку, дату). Вызываются в виде SELECT dbo.ИмяФункции(параметры).
  2. Табличные функции (TVF) — возвращают виртуальную таблицу. Вызываются как обычные таблицы: SELECT * FROM dbo.ИмяФункции(параметры).

Если вы пытаетесь вызвать скалярную функцию через SELECT * FROM..., SQL Server выдаст ошибку "Invalid object name", так как он ожидает увидеть таблицу или представление, а получает скалярный объект. Если же вы вызываете скалярную функцию правильно (через SELECT без FROM), но не указываете псевдоним (alias), то в полученном Recordset поле будет называться либо по имени функции, либо вовсе не будет иметь имени, что приведет к ошибке в 1С при попытке обращения RS.Fields("ИмяПоля").Value.

Разбор типового кода для работы с ADO

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


Соединение = SQLServer.Подключиться();
Command = Новый COMОбъект("ADODB.Command");
RS = Новый COMОбъект("ADODB.RecordSet");

Command.ActiveConnection = Соединение;
Command.CommandType = 1; // adCmdText
Command.NamedParameters = True;

// Здесь кроется проблема выбора синтаксиса:
Command.CommandText = "SELECT [dbo].[ProductID](?, ?) AS prd_ID";

// Настройка параметров
Парам1 = Command.CreateParameter("@Barcode", 202, 1, 40, "22663484730011"); 
Command.Parameters.Append(Парам1);

Парам2 = Command.CreateParameter("@DepositorID", 3, 1, , 32); 
Command.Parameters.Append(Парам2);

RS = Command.Execute();

Пока НЕ RS.EOF() Цикл
    // Обращаемся по псевдониму, который указали в SELECT
    prd_ID = RS.Fields("prd_ID").Value; 
    RS.MoveNext();
КонецЦикла;

Вариант 1: Использование литералов в тексте запроса

Если структура запроса простая и данные не требуют сложной типизации, можно вставить значения параметров прямо в текст запроса. Рассмотрим, как это сделать, чтобы избежать лишней сложности с объектами ADODB.Parameter. Выясним причину популярности этого метода: он нагляден и позволяет быстро проверить работу функции в SQL Server Management Studio перед переносом в 1С.

Пример вызова скалярной функции с литералами:


ТекстЗапроса = "SELECT [dbo].[ProductID]('" + Штрихкод + "', " + Идентификатор + ") AS prd_ID";
Command.CommandText = ТекстЗапроса;
RS = Command.Execute();

Важный нюанс: при использовании этого метода необходимо самостоятельно следить за экранированием кавычек в строковых параметрах, чтобы не допустить SQL-инъекций или синтаксических ошибок.

Вариант 2: Правильная работа с параметрами и псевдонимами

Проанализируем более профессиональный подход — использование знаков вопроса (?) в качестве заглушек (placeholders). Это позволяет драйверу SQL Server ODBC или OLE DB самостоятельно позаботиться о типах данных.

Когда мы выполняем SELECT [dbo].[ProductID](?, ?), SQL Server возвращает колонку без заданного имени. Чтобы 1С могла обратиться к полю по имени, обязательно используйте конструкцию AS ИмяПоля.

Разберем настройки параметров подробнее:

Использование драйверов и NamedParameters

Стоит отметить, что свойство Command.NamedParameters = True не всегда работает так, как ожидается. Многие драйверы (особенно старые версии MSDASQL) игнорируют имена параметров (типа @Barcode) и просто сопоставляют их по порядку следования знаков вопроса в тексте запроса. Поэтому крайне важно добавлять параметры через Command.Parameters.Append ровно в том порядке, в котором они перечислены в функции SQL.

Синтаксис для табличных функций

Если ваша функция возвращает таблицу (Table-Valued Function), то синтаксис SELECT * FROM будет верным. В этом случае псевдонимы полей обычно уже определены внутри самой функции, и вы можете обращаться к ним напрямую.


// Пример для табличной функции
Command.CommandText = "SELECT prd_ID, prd_Name FROM [dbo].[GetProductData](?, ?)";
// ... добавление параметров ...
RS = Command.Execute();
Если НЕ RS.EOF() Тогда
    Имя = RS.Fields("prd_Name").Value;
КонецЕсли;

Заключение и рекомендации

Рассмотрев все нюансы, мы можем сформулировать основные правила успешного вызова SQL-функций из 1С:

  1. Определите тип функции: Если она скалярная, используйте SELECT, если табличная — SELECT FROM.
  2. Назначайте псевдонимы: Всегда добавляйте AS MyFieldName для скалярных результатов, чтобы Recordset вернул именованное поле.
  3. Соблюдайте порядок: Добавляйте параметры в коллекцию Parameters в строгом соответствии с их порядком в SQL-функции.
  4. Проверяйте типы: Используйте 202 для юникод-строк и 3 для целых чисел, чтобы избежать ошибок неявного преобразования типов на стороне сервера.

Следуя этим правилам, вы сможете избежать многочасовых поисков ошибок и обеспечить стабильную работу интеграции между 1С и SQL Server.

← На главную