При интеграции 1С с внешними базами данных Microsoft SQL Server разработчики нередко сталкиваются с ситуацией, когда один и тот же SQL-запрос успешно возвращает строки в среде SQL Server Management Studio (SSMS), но при выполнении через COM-объект ADODB.Connection из кода 1С возвращает пустую выборку без каких-либо ошибок. Разберем по шагам причины такого поведения и рассмотрим надежные способы получения данных.
Проанализируем основную причину несовпадения результатов в SSMS и 1С. В консоли управления запрос чаще всего выполняется под учетной записью администратора (например, sa) или с использованием доменной аутентификации Windows. В коде 1С подключение обычно настраивается под выделенным техническим пользователем SQL Server с ограниченными привилегиями.
Обратим внимание на следующие критические факторы безопасности СУБД:
VIEW) использует системные функции (такие как SUSER_SNAME(), USER_NAME()) или политики безопасности строк (Row-Level Security), SQL Server динамически фильтрует строки. Ограниченный пользователь 1С не увидит записей, тогда как администратор в SSMS получит полный список.SELECT на представление — необходимо явно выдать права на чтение всех связанных таблиц.JOIN. При отсутствии прав на одну из связываемых таблиц запрос может отсекать все строки.При выполнении команд через ADO на стороне SQL Server могут генерироваться служебные сообщения о количестве обработанных строк (DONE_IN_PROC). Это происходит при наличии триггеров или пакетных инструкций. В результате объект ADODB.Recordset принимает первым не набор данных с результатом выборки, а пустой служебный маркер.
Чтобы исключить влияние служебных пакетов, всегда добавляем директиву SET NOCOUNT ON; в самое начало текста запроса перед оператором SELECT.
Выясним, как правильно инициализировать набор данных. По умолчанию при выполнении через метод Execute() объекта ADODB.Command или ADODB.Connection создается однонаправленный курсор (forward-only), который в ряде конфигураций драйверов может вести себя некорректно при попытке позиционирования. Рекомендуется явно создавать ADODB.RecordSet и задавать статический курсор CursorType = 3 (adOpenStatic).
Посмотрим на пример универсальной функции для подключения к MS SQL Server, выполнения запроса и выгрузки результата в ТаблицаЗначений:
Функция ВыполнитьПрямойЗапросSQL(Сервер, База, Пользователь, Пароль, ТекстЗапроса) Экспорт
// 1. Инициализируем соединение
Подключение = Новый COMОбъект("ADODB.Connection");
Подключение.Provider = "SQLOLEDB.1";
Подключение.Properties("Data Source").Value = СокрЛП(Сервер);
Подключение.Properties("Initial Catalog").Value = СокрЛП(База);
Подключение.Properties("User ID").Value = СокрЛП(Пользователь);
Подключение.Properties("Password").Value = СокрЛП(Пароль);
Попытка
Подключение.Open();
Исключение
ВызватьИсключение "Ошибка подключения к MS SQL: " + ОписаниеОшибки();
КонецПопытки;
// 2. Настраиваем и открываем выборку
ЗаписиSQL = Новый COMОбъект("ADODB.RecordSet");
ЗаписиSQL.CursorType = 3; // adOpenStatic
// Добавляем SET NOCOUNT ON для исключения пустых служебных пакетов
ТекстSQL = "SET NOCOUNT ON; " + ТекстЗапроса;
Попытка
ЗаписиSQL.Open(ТекстSQL, Подключение);
Исключение
Подключение.Close();
ВызватьИсключение "Ошибка выполнения SQL-запроса: " + ОписаниеОшибки();
КонецПопытки;
// 3. Формируем структуру результирующей ТаблицыЗначений
Таблица = Новый ТаблицаЗначений;
КоличествоКолонок = ЗаписиSQL.Fields.Count - 1;
Для НомерПоля = 0 По КоличествоКолонок Цикл
ПолеSQL = ЗаписиSQL.Fields.Item(НомерПоля);
Таблица.Колонки.Добавить(ПолеSQL.Name);
КонецЦикла;
// 4. Заполняем строки
Пока НЕ ЗаписиSQL.EOF Цикл
НоваяСтрока = Таблица.Добавить();
Для НомерПоля = 0 По КоличествоКолонок Цикл
НоваяСтрока[НомерПоля] = ЗаписиSQL.Fields.Item(НомерПоля).Value;
КонецЦикла;
ЗаписиSQL.MoveNext();
КонецЦикла;
// 5. Закрываем соединения
ЗаписиSQL.Close();
Подключение.Close();
Возврат Таблица;
КонецФункции
Рассмотрим распространенные детали реализации, приводящие к скрытым ошибкам:
EOF объекта Recordset возвращает булево значение. В условиях циклов 1С следует писать Пока НЕ ЗаписиSQL.EOF Цикл, а не сравнивать его с числом 0.YYYYMMDD или YYYY-MM-DDTHH:MM:SS. Это предотвращает искажение условий фильтрации из-за различий в региональных настройках (Language/DateFormat) сеанса SQL-сервера.ragent. Убедимся, что на сервере установлены соответствующие 64-битные OLE DB провайдеры (например, MSOLEDBSQL) или ODBC-драйверы.