Как в 1С 7.7 через 1С++ выполнить прямой SQL-запрос к другой базе данных с разбором метаимен

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

При разработке отчетов и механизмов интеграции в среде 1С:Предприятия 7.7 с использованием внешней компоненты 1С++ нередко возникает задача получить данные из другой информационной базы. При этом разработчики стремятся сохранить удобство использования метапарсера, чтобы писать запросы с конструкциями вида $Справочник.Контрагенты или $Документ.Поставка, не выясняя вручную идентификаторы таблиц и полей в чужой структуре данных.

В этой статье мы подробно рассмотрим, как правильно подключиться к сторонней базе данных (SQL или файловой), подключить её файл метаданных (1Cv7.md) к парсеру и избежать распространенных ошибок авторизации.

Вариант 1. Прямое подключение к сторонней базе через метод ПрисоединитьИБ

Самый простой и эффективный способ работы с удаленной базой данных — использование метода ПрисоединитьИБ объекта ODBCDatabase. Этот метод считывает файл параметров базы 1Cv7.dba и структуру метаданных 1Cv7.md из указанного каталога, настраивая метапарсер ODBCRecordSet на работу со схемой удаленной базы.

Разберем по шагам правильную последовательность вызовов:

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

Посмотрим на рабочий пример кода функции для выгрузки данных из складской базы:


Функция ПолучитьДанныеСклада(НачДата)
    Перем Результат;
    
    Результат = СоздатьОбъект("ТаблицаЗначений");
    Результат.НоваяКолонка("УИД", "Строка", 9);
    Результат.НоваяКолонка("Документ_дата", "Дата");
    
    Каталог1С = "\\ServerName\base\sklad\";     
    СерверSQL = "SQL-SERVER-01";
    БазаSQL   = "sklad2014";
    userSQL   = "sa";
    pwdSQL    = "SecretPass123";    
    
    БазаПодкл = СоздатьОбъект("ODBCDatabase");
    СтрокаСоединения = "DRIVER=SQL Server;SERVER=" + СокрЛП(СерверSQL) + ";UID=" + СокрЛП(userSQL) + ";PWD=" + СокрЛП(pwdSQL) + ";DATABASE=" + СокрЛП(БазаSQL) + ";";
    
    Если БазаПодкл.Соединение(СтрокаСоединения) = 0 Тогда         
        Сообщить("Не удалось подключиться к базе " + БазаSQL + " - проверьте параметры подключения!");
        Возврат Результат;
    КонецЕсли;
    
    // Присоединяем каталог базы для инициализации метапарсера
    БазаПодкл.ПрисоединитьИБ(Каталог1С);
    
    ЗапросСклад = СоздатьОбъект("ODBCRecordSet");
    ЗапросСклад.УстБД(БазаПодкл);
    
    ТекстЗапроса = "
    |SELECT $Поставка.УИД УИД
    |    , MAX(NullIf(Cast(Left(Журнал.DATE_TIME_IDDOC, 8) AS datetime), '17530101')) Документ_дата
    |FROM $Документ.ВводОВХ AS ВводОВХ With (NOLOCK)
    |    INNER JOIN $Документ.Поставка AS Поставка With (NOLOCK) ON $ВводОВХ.Основание = $ВидДокумента36.Поставка + Поставка.IDDOC
    |    INNER JOIN _1SJOURN AS Журнал With (NOLOCK) ON ВводОВХ.IDDOC = Журнал.IDDOC
    |WHERE (Журнал.DATE_TIME_IDDOC >= :д1) AND ((Журнал.CLOSED & 1) = 1)
    |GROUP BY
    |    $Поставка.УИД
    |";
    
    ЗапросСклад.УстановитьТекстовыйПараметр("д1", ДобавитьМесяц(НачДата, -12));
    ЗапросСклад.ВыполнитьИнструкцию(ТекстЗапроса, Результат);
    
    Возврат Результат;
КонецФункции

Ошибка «Введенный пароль неверен» при вызове ПрисоединитьИБ

При обращении к базам филиалов разработчики часто сталкиваются с ошибкой «Введенный пароль неверен» на строке БазаПодкл.ПрисоединитьИБ(Каталог1С), хотя через SQL Management Studio или Query Analyzer соединение по логину и паролю SQL проходит успешно.

Выясним причину такого поведения. Метод ПрисоединитьИБ открывает служебный файл 1Cv7.dba, в котором хранятся системные параметры подключения базы к СУБД. Эти данные зашифрованы внутренними механизмами платформы 1С. Для их расшифровки требуются логин и пароль пользователя 1С:Предприятия, а не учетной записи SQL Server.

Синтаксис метода с явным указанием учетных данных пользователя 1С:

БазаПодкл.ПрисоединитьИБ(КаталогИБ, ИмяПользователя1С, ПарольПользователя1С);

Если в удаленной базе настроен список пользователей, необходимо передать имя и пароль пользователя 1С, у которого есть права на открытие конфигурации (например, пользователя с административными правами). При пустом списке пользователей параметры можно опустить.

Вариант 2. Выполнение кросс-базового запроса с разбором метаданных двух баз (MetaDataWork)

Иногда требуется в рамках одной SQL-инструкции объединить данные текущей базы и базы другого филиала (например, если они расположены на одном SQL-сервере или соединены через механизм Linked Server). По умолчанию метапарсер компоненты 1С++ умеет транслировать метаимена только одной конфигурации за один проход.

Проанализируем методику обработки текста запроса в два этапа с помощью двух независимых объектов MetaDataWork:

  1. Обозначаем метаимена текущей конфигурации стандартным символом $.
  2. Метаимена удаленной конфигурации временно помечаем альтернативным символом, например @.
  3. Обрабатываем запрос первым объектом MetaDataWork (он преобразует имена текущей базы).
  4. Создаем второй объект MetaDataWork, подключаем к нему файл 1Cv7.md удаленной базы с помощью метода ПрисоединитьМД().
  5. Заменяем символ @ обратно на $ и повторно вызываем метод ОбрМетаСКЛ() для преобразования имен удаленной базы.
  6. Выполняем итоговый SQL-текст через ODBCRecordSet.

Посмотрим на практический пример кросс-базового запроса:


Процедура СформироватьКроссЗапрос()
    Перем рс, ТекстЗапроса, глМД, глМД2, ПутьКБазе2, ТабРез;
    
    рс = СоздатьОбъект("ODBCRecordSet");
    
    // В тексте запроса:
    // $ - метаданные текущей базы
    // @ - метаданные второй (удаленной) базы
    ТекстЗапроса = "
    |SELECT
    |    СпрНаш.DESCR AS КлиентВТекущейБазе
    |    , СпрУдал.DESCR AS КлиентВУдаленнойБазе
    |FROM $Справочник.Контрагенты AS СпрНаш With (NOLOCK)
    |LEFT JOIN DatabaseBranch.dbo.@Справочник.Контрагенты AS СпрУдал With (NOLOCK) 
    |    ON СпрНаш.CODE = СпрУдал.CODE
    |";    
    
    // Шаг 1: Парсим метаимена текущей базы
    глМД = СоздатьОбъект("MetaDataWork");
    ТекстЗапроса = глМД.ОбрМетаСКЛ(ТекстЗапроса);
    
    // Шаг 2: Подключаем MD второй базы и парсим оставшиеся метаимена
    глМД2 = СоздатьОбъект("MetaDataWork");
    ПутьКБазе2 = "\\ServerName\base\branch\";
    глМД2.ПрисоединитьМД(ПутьКБазе2 + "1Cv7.md");
    
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "@", "$");
    ТекстЗапроса = глМД2.ОбрМетаСКЛ(ТекстЗапроса);
    
    // Шаг 3: Выполняем готовый T-SQL запрос
    ТабРез = рс.ВыполнитьИнструкцию(ТекстЗапроса);
    ТабРез.ВыбратьСтроку();
КонецПроцедуры

Универсальная функция подключения к базам различных типов

Для оптимизации кода конфигурации и централизованного создания соединений (SQL Server, OLE DB, DBF, SQLite) удобно использовать универсальную функцию-обертку. Она инициализирует подключение и возвращает готовый к работе объект запроса.

Рассмотрим реализацию такой функции:


Функция глСоединение(ТипСоединения = "", ПутьИБ = "", Пользователь = "Admin", Пароль = "123456", ИмяСервера = "") Экспорт
    Перем БД, Запрос, Команда, СтрокаСоединения, МФ;
    
    Если ВРег(ТипСоединения) = "SQL" Тогда
        Попытка
            БД = СоздатьОбъект("ODBCDataBase");
            Запрос = СоздатьОбъект("ODBCRecordSet");
            Если ПустоеЗначение(ПутьИБ) = 0 Тогда
                БД.ПрисоединитьИБ(ПутьИБ, Пользователь, Пароль);
                Запрос.УстБД(БД);
            КонецЕсли;
            Возврат Запрос;
        Исключение
            Сообщить("Ошибка инициализации соединения SQL: " + ОписаниеОшибки(), "!");
            Возврат 0;
        КонецПопытки;
        
    ИначеЕсли ВРег(ТипСоединения) = "SQL_DIRECT" Тогда
        Попытка
            БД = СоздатьОбъект("ODBCDataBase");
            Запрос = СоздатьОбъект("ODBCRecordSet");
            СтрокаСоединения = "Driver={SQL Server};Server=" + ИмяСервера + ";Database=" + ПутьИБ + ";Uid=" + Пользователь + ";Pwd=" + Пароль + ";";
            БД.Соединение(СтрокаСоединения);
            Запрос.УстБД(БД);
            Возврат Запрос;
        Исключение
            Сообщить("Ошибка прямого ODBC-соединения: " + ОписаниеОшибки(), "!");
            Возврат 0;
        КонецПопытки;
        
    ИначеЕсли ВРег(ТипСоединения) = "ДБФ" Тогда
        Попытка
            БД = СоздатьОбъект("ODBCDataBase");
            Если ПустоеЗначение(ПутьИБ) = 0 Тогда
                БД.ПрисоединитьИБ(ПутьИБ);
            Иначе
                БД.Соединение("DRIVER={Microsoft Visual FoxPro Driver};Deleted=Yes;Null=Yes;Collate=RUSSIAN;Exclusive=No;SourceType=DBF;SourceDB=" + КаталогИБ());
            КонецЕсли;
            Запрос = СоздатьОбъект("ODBCRecordSet");
            Запрос.УстБД(БД);
            Возврат Запрос;
        Исключение
            Сообщить("Ошибка подключения к DBF: " + ОписаниеОшибки(), "!");
            Возврат 0;
        КонецПопытки;
        
    Иначе
        МФ = СоздатьОбъект("MetaInfoClasses");
        Если МФ.ЭтоSQL_Версия() = 1 Тогда
            Возврат глСоединение("SQL");
        Иначе
            Возврат глСоединение("ДБФ");
        КонецЕсли;
    КонецЕсли;
КонецФункции

Особенности и ограничения

Обратите внимание на технические нюансы при работе со сторонними структурами метаданных:

  1. Сетевой доступ: Методы ПрисоединитьИБ и ПрисоединитьМД требуют наличия прямого доступа по протоколу SMB к каталогу с базой для чтения файлов 1Cv7.md и 1Cv7.dba. Если доступен только SQL-порт (TCP 1433), следует скопировать файл 1Cv7.md локально и использовать ручную обработку текста через MetaDataWork.ПрисоединитьМД() в связке с прямым ODBC-соединением.
  2. Типизация колонок: Автоматическая типизация вида [Ссылка $Справочник.Номенклатура] корректно возвращает рабочие ссылки только для текущей базы. Для удаленной базы парсер вернет строковые или числовые идентификаторы объектов (ID), так как контекст сторонней базы в запущенном сеансе 1С не поддерживается.
← На главную