Как сделать прямой SQL-запрос к сторонней базе данных из 1С 7.7 без OLE?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При интеграции нескольких информационных баз на платформе 1С:Предприятие 7.7 разработчики часто сталкиваются с проблемой медленной передачи данных. Традиционное OLE-соединение (COM-соединение) обладает существенными недостатками: оно требует запуска еще одного полновесного экземпляра программы 1С, расходует лицензии, работает крайне медленно на больших объемах данных и подвержено внезапным зависаниям. К счастью, если базы данных работают под управлением СУБД MS SQL Server, мы можем обойти эти ограничения и настроить высокоскоростное прямое взаимодействие на уровне SQL.

В этой статье мы подробно разберем, как реализовать прямые и непрямые SQL-запросы к сторонней базе данных из 1С 7.7. Мы рассмотрим три основных сценария: от простых системных механизмов ADO до мощных возможностей внешней компоненты 1С++ (1cpp.dll), которая умеет автоматически разбирать метаданные сторонних баз.

Способ 1. Быстрый запрос в рамках одного MS SQL Server

Если обе базы данных (рабочая и сторонняя) расположены на одном физическом сервере СУБД, нам не обязательно подключать сложные внешние библиотеки. Мы можем обратиться к таблицам соседней базы напрямую через язык T-SQL, используя полное имя таблицы СУБД.

В MS SQL Server к таблицам любой базы на текущем сервере можно обратиться по следующему шаблону:

[Имя_Сторонней_Базы].[Схема_Данных].[Имя_Таблицы]

Схемой данных по умолчанию в базах 1С практически всегда является dbo. Разберем по шагам, как написать такой запрос. Главная сложность здесь заключается в том, что физические имена таблиц (например, справочников или документов) в разных базах генерируются платформой динамически. Если конфигурации абсолютно идентичны, то и имена таблиц совпадут. В таком случае мы можем использовать метапарсер нашей текущей базы для генерации запроса к сторонней базе.

Проанализируем пример кода на языке 1С 7.7 с использованием стандартного класса ODBCRecordset из компоненты 1С++:


// Создаем объект для выполнения прямого запроса
Запрос = СоздатьОбъект("ODBCRecordset");

// Формируем текст запроса к сторонней базе "Trade_DB"
// Предполагаем, что конфигурации баз абсолютно одинаковы
ТекстЗапроса = "
|SELECT 
|    ExtContr.ID as [Ссылка],
|    ExtContr.CODE as [Код],
|    ExtContr.DESCR as [Наименование]
|FROM 
|    Trade_DB.dbo.$Справочник.Контрагенты AS ExtContr (NOLOCK)
|WHERE 
|    ExtContr.ISFOLDER = 2
|";

// Выполняем запрос и выгружаем результат в Таблицу Значений
ТЗ = СоздатьОбъект("ТаблицаЗначений");
Если Запрос.Открыть(ТекстЗапроса, ТЗ) = 1 Тогда
    ТЗ.ВыбратьСтроки();
    Пока ТЗ.ПолучитьСтроку() = 1 Цикл
        Сообщить("Контрагент из сторонней базы: " + ТЗ.Наименование);
    КонецЦикла;
Иначе
    Сообщить("Ошибка выполнения запроса: " + Запрос.ПолучитьОписаниеОшибки());
КонецЕсли;

Важное примечание: Этот способ работает идеально только в том случае, если структуры метаданных синхронны, и парсер 1С++ корректно заменяет конструкцию $Справочник.Контрагенты на реальное физическое имя таблицы (например, SC128), которое совпадает в обеих базах. Если конфигурации различаются, этот подход использовать нельзя, так как парсер подставит имя таблицы из текущей базы, а в сторонней базе под этим именем может находиться совершенно другой объект или таблица вообще будет отсутствовать.

Способ 2. Использование компоненты 1С++ и класса ODBCDatabase (для разных конфигураций)

Что делать, если конфигурации баз различаются, или они расположены на разных серверах? Самым надежным и профессиональным решением является использование класса ODBCDatabase из библиотеки 1С++.

Этот класс обладает уникальным методом ПрисоединитьИБ(). Метод принимает на вход путь к каталогу сторонней информационной базы 1С 7.7. Компонента самостоятельно считывает файл метаданных (1Cv7.MD) и структуру таблиц (1Cv7.DDS) удаленной базы. Это позволяет писать SQL-запросы к сторонней базе, используя привычные метаимена (с символом $), даже если конфигурации полностью различаются!

Рассмотрим подробнее по шагам, как настроить такое подключение:

  1. Создаем объект ODBCDatabase для связи со сторонней базой.
  2. Вызываем метод ПрисоединитьИБ(), передавая путь к каталогу, имя пользователя и пароль SQL.
  3. Создаем стандартный объект ODBCRecordset.
  4. Связываем рекордсет с подключенной базой данных с помощью метода УстБД().
  5. Выполняем запрос с использованием метаимен сторонней базы.

Посмотрим на пример практической реализации данного метода:


// Шаг 1: Инициализируем подключение к сторонней базе данных
БД_Сторонняя = СоздатьОбъект("ODBCDatabase");

ПутьККаталогуБазы = "ВыборКаталогаИБ\Database_Folder\"; // Укажите реальный путь к сетевой папке базы
ПользовательSQL = "sa";
ПарольSQL = "MyStrongPassword123";

// Шаг 2: Присоединяем информационную базу для чтения метаданных
Если БД_Сторонняя.ПрисоединитьИБ(ПутьККаталогуБазы, ПользовательSQL, ПарольSQL) = 0 Тогда
    Предупреждение("Не удалось прочитать структуру метаданных сторонней базы данных!");
    Возврат;
КонецЕсли;

// Шаг 3: Создаем объект для выполнения SQL-запроса
Запрос = СоздатьОбъект("ODBCRecordset");

// Шаг 4: Указываем контекст выполнения запроса (сторонняя база)
Запрос.УстБД(БД_Сторонняя);

// Шаг 5: Формируем текст запроса. 
// Теперь парсер переведет метаимена в физические таблицы удаленной базы!
ТекстЗапроса = "
|SELECT 
|    Спр.ID as [Ссылка],
|    Спр.CODE as [Код],
|    Спр.DESCR as [Наименование],
|    $Спр.ИНН as [ИНН]
|FROM 
|    $Справочник.Контрагенты AS Спр (NOLOCK)
|WHERE 
|    Спр.ISFOLDER = 2
|";

ТЗ = СоздатьОбъект("ТаблицаЗначений");
Если Запрос.Открыть(ТекстЗапроса, ТЗ) = 1 Тогда
    Сообщить("Успешно получено строк: " + ТЗ.КоличествоСтрок());
    ТЗ.ВыбратьСтроки();
    Пока ТЗ.ПолучитьСтроку() = 1 Цикл
        Сообщить("Контрагент: " + ТЗ.Наименование + " | ИНН: " + ТЗ.ИНН);
    КонецЦикла;
Иначе
    Сообщить("Ошибка при выполнении запроса: " + Запрос.ПолучитьОписаниеОшибки());
КонецЕсли;

Этот метод невероятно удобен. Он полностью избавляет разработчика от необходимости вручную сопоставлять имена таблиц (SC***) и реквизитов (SP***) в сторонней базе данных. Вся черновая работа по сопоставлению ложится на плечи парсера метаданных 1С++.

Способ 3. Прямой доступ без внешних компонент через ADO (ActiveX Data Objects)

Иногда возникают ситуации, когда на рабочих станциях пользователей запрещено регистрировать сторонние динамические библиотеки (DLL), такие как 1cpp.dll, из-за политик безопасности домена. В этом случае мы можем решить задачу силами самой операционной системы Windows, используя технологию ADO.

Объекты ADODB.Connection и ADODB.Recordset встроены в Windows и доступны "из коробки". Главный недостаток этого метода — полное отсутствие парсера метаданных. Нам придется писать запрос на чистом T-SQL, используя только физические имена таблиц и полей сторонней базы (например, SC240 вместо $Справочник.Номенклатура).

Выяснить физические имена таблиц можно, открыв файл 1Cv7.DDS в каталоге сторонней базы обычным текстовым редактором, либо сделав предварительный анализ структуры таблиц в SQL Server Management Studio (SSMS).

Выполним подключение по шагам через ADO:


// Создаем COM-объекты для работы с базой данных
Соединение = СоздатьОбъект("ADODB.Connection");
НаборЗаписей = СоздатьОбъект("ADODB.Recordset");

// Формируем строку подключения к SQL-серверу
СтрокаПодключения = "Provider=SQLOLEDB.1;" + 
                    "Data Source=Имя_Или_IP_Сервера_SQL;" + 
                    "Initial Catalog=Имя_Базы_Данных_SQL;" + 
                    "User ID=sa;" + 
                    "Password=Пароль_Пользователя_SQL;";

Попытка
    Соединение.Open(СтрокаПодключения);
Исключение
    Предупреждение("Не удалось установить соединение с сервером базы данных: " + ОписаниеОшибки());
    Возврат;
КонецПопытки;

// Пишем прямой SQL-запрос с физическими именами таблиц.
// В примере SC142 - это таблица справочника Контрагенты в сторонней БД.
ТекстЗапроса = "
|SELECT 
|    SC142.CODE, 
|    SC142.DESCR 
|FROM 
|    SC142 (NOLOCK) 
|WHERE 
|    SC142.ISFOLDER = 2
|";

Попытка
    // Выполняем запрос
    НаборЗаписей.Open(ТекстЗапроса, Соединение, 1, 1); // adOpenKeyset, adLockReadOnly
Исключение
    Сообщить("Ошибка выполнения запроса SQL: " + ОписаниеОшибки());
    Соединение.Close();
    Возврат;
КонецПопытки;

// Обходим полученный набор данных
Пока НаборЗаписей.EOF = 0 Цикл
    Код = СокрЛП(НаборЗаписей.Fields("CODE").Value);
    Наименование = СокрЛП(НаборЗаписей.Fields("DESCR").Value);
    
    Сообщить("Получено по ADO -> Код: " + Код + " | Название: " + Наименование);
    НаборЗаписей.MoveNext();
КонецЦикла;

// Обязательно закрываем соединения для высвобождения ресурсов сервера
НаборЗаписей.Close();
Соединение.Close();

Этот способ незаменим для простых перегрузок данных, когда состав полей редко меняется, и нет возможности развернуть полноценную среду разработки с интеграцией сторонних DLL на всех клиентских машинах.

Решение проблемы разных физических серверов: Связанные серверы (Linked Servers)

Если базы находятся на разных физических серверах, то помимо прямого указания IP-адреса в строке подключения ADO или 1С++, администраторы баз данных часто используют механизм Linked Server (Связанный сервер) на уровне самого MS SQL Server.

Связав сервера один раз на уровне СУБД, мы получаем возможность обращаться к удаленной базе в рамках стандартных запросов первого способа. Синтаксис обращения будет выглядеть так:

[Имя_Удаленного_Сервера].[Имя_Базы].[dbo].[Имя_Таблицы]

Это позволяет объединять данные из локальной и удаленной баз в одном SQL-запросе с помощью операторов JOIN, что обеспечивает феноменальную скорость обработки распределенной информации.

Важное предупреждение по безопасности: Операции записи (INSERT, UPDATE)

Прямые SQL-запросы позволяют не только считывать информацию (оператор SELECT), но и модифицировать ее напрямую в СУБД. Мы крайне не рекомендуем выполнять операции прямой записи данных в таблицы сторонних баз 1С 7.7.

Запись напрямую в таблицы SQL минует внутреннюю бизнес-логику платформы 1С:

Если вам необходимо передать данные в стороннюю базу с возможностью записи, лучшим решением будет использование транзитных таблиц СУБД. Вы записываете информацию из текущей базы в нейтральную таблицу SQL, а целевая база забирает эти данные и проводит их через свои штатные механизмы (например, через регламентное задание по OLE или XML).

← На главную