При интеграции 1С с внешними базами данных Microsoft SQL Server часто используется прямое подключение через COM-объекты ADODB.Connection и ADODB.Command. Типичная задача — запустить хранимую процедуру и получить результат ее работы. Однако нередко разработчики сталкиваются с ситуацией, когда метод Execute() возвращает объект Recordset, но количество полей в нем равно нулю (RS.Fields.Count = 0), а обращение к значениям вызывает ошибку контекста.
Разберем причины такого поведения и рассмотрим подробные способы получения результата выполнения процедуры.
В MS SQL Server результат работы процедуры может формироваться несколькими способами:
SELECT): процедура возвращает строки таблицы. Если внутри процедуры выполняются операции INSERT, UPDATE или DELETE без директивы SET NOCOUNT ON, SQL Server отправляет клиенту служебные сообщения о количестве обработанных строк. Провайдер ADODB воспринимает каждое такое сообщение как отдельный закрытый набор записей, из-за чего первый полученный Recordset оказывается пустым.RETURN): процедура возвращает целочисленный статус. Данный код не попадает в выборку Recordset, а возвращается через специальный системный параметр команды.OUTPUT): данные передаются обратно через именованные переменные процедуры.Если хранимая процедура возвращает данные через оператор SELECT, для чтения значений необходимо спозиционироваться на первой строке выборки и последовательно обойти строки с помощью методов MoveFirst() и MoveNext().
Посмотрим на пример корректного чтения данных:
// Предполагается, что RS получен в результате Command.Execute()
Если RS.State = 1 Тогда // 1 = adStateOpen (набор открыт)
Если Не RS.EOF Тогда
RS.MoveFirst();
Пока Не RS.EOF Цикл
// Получаем значение первой колонки (индексация с 0)
ВозвращаемоеЗначение = RS.Fields(0).Value;
// Выполняем переход к следующей записи
RS.MoveNext();
КонецЦикла;
КонецЕсли;
КонецЕсли;
Если текст процедуры недоступен для редактирования и в ней происходят промежуточные манипуляции с данными без подавления счетчиков строк, необходимо перебрать наборы данных до тех пор, пока не будет найден открытый Recordset с реальными полями.
Разберем по шагам, как организовать безопасный перебор наборов:
Пока RS <> Неопределено И RS.State <> 0 Цикл
// Проверяем, содержит ли текущий набор поля
Если RS.Fields.Count > 0 Тогда
Если Не RS.EOF Тогда
RS.MoveFirst();
ВозвращаемоеЗначение = RS.Fields(0).Value;
Прервать;
КонецЕсли;
КонецЕсли;
// Переходим к следующему результирующему набору
RS = RS.NextRecordset();
КонецЦикла;
Когда исходный код процедуры закрыт и неизвестно, как именно она возвращает статус (через RETURN или выходной параметр), самым простым решением является вызов процедуры внутри короткого скрипта T-SQL с явным выводом результата в SELECT и отключением служебных сообщений.
Рассмотрим пример формирования такой команды:
Команда = Новый COMОбъект("ADODB.Command");
Команда.ActiveConnection = Соединение;
Команда.CommandType = 1; // 1 = adCmdText
// Заворачиваем вызов в скрипт T-SQL
ТекстЗапроса =
"SET NOCOUNT ON;
|DECLARE @Result INT;
|EXEC @Result = dbo.ИмяПроцедуры;
|SELECT @Result AS ReturnCode;";
Команда.CommandText = ТекстЗапроса;
RS = Команда.Execute();
Если RS.State = 1 И Не RS.EOF Тогда
ВозвращаемоеЗначение = RS.Fields("ReturnCode").Value;
RS.Close();
КонецЕсли;
Если известно, что процедура использует стандартный механизм RETURN <значение>, значение можно прочитать напрямую через коллекцию параметров Parameters объекта ADODB.Command.
Разберем настройку команды с параметром возврата:
Команда = Новый COMОбъект("ADODB.Command");
Команда.ActiveConnection = Соединение;
Команда.CommandText = "dbo.ИмяПроцедуры";
Команда.CommandType = 4; // 4 = adCmdStoredProc
// Создаем параметр для кода возврата:
// Имя: "ReturnValue"
// Тип: 3 (adInteger)
// Направление: 4 (adParamReturnValue)
ПараметрВозврата = Команда.CreateParameter("ReturnValue", 3, 4);
Команда.Parameters.Append(ПараметрВозврата);
RS = Команда.Execute();
// Если процедура возвращала и Recordset, его нужно закрыть,
// чтобы гарантировать заполнение параметров
Если RS.State = 1 Тогда
RS.Close();
КонецЕсли;
КодВозврата = Команда.Parameters("ReturnValue").Value;
При использовании COM-объектов ADODB важно помнить о следующих нюансах:
MSOLEDBSQL или SQLNCLI11).