Как в 1С 7.7 связать внешнюю таблицу DBF и базу данных SQL в одном запросе

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

При работе в среде 1С:Предприятие 7.7 программисты часто сталкиваются с задачей объединения данных, которые хранятся в разных форматах. Типичная ситуация: основная база данных работает на MS SQL Server, но часть информации (например, прайс-листы поставщиков или выгрузки из сторонних программ) поступает в формате DBF. Попытка выполнить прямой SQL-запрос, объединяющий эти источники через стандартный OLEDBCommand, часто приводит к ошибке: FAILED! ICommandText::Execute(): File 'table.dbf' does not exist.

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

Почему не работает прямое соединение?

Разберем ситуацию, описанную в исходном сообщении. Когда мы создаем объект OLEDBData и указываем строку соединения с провайдером VFPOLEDB.1 (Visual FoxPro OLE DB Provider), мы фактически создаем канал связи с файловой системой. Этот провайдер «понимает» DBF-файлы в указанном каталоге, но он абсолютно ничего не знает о таблицах, которые находятся внутри вашего SQL Server. Для него sc709.dbf — это физический файл на диске, а не таблица справочника в SQL.

И наоборот: если мы подключаемся к SQL-серверу через SQLOLEDB, сервер видит свои внутренние таблицы, но не может напрямую «прочитать» DBF-файл, лежащий в произвольной папке на клиентском компьютере, без специальных настроек.

Решение 1: Использование временных таблиц в MS SQL

Рассмотрим подход, предложенный в обсуждении: предварительную загрузку данных во временную таблицу SQL. Это самый надежный метод, так как после загрузки данных обе таблицы (бывшая DBF и штатная SQL) оказываются в одном контексте, и мы можем использовать всю мощь JOIN.

Разберем процесс по шагам:

  1. Создаем временную таблицу в SQL-базе с нужной структурой.
  2. Читаем данные из DBF-файла (построчно или пакетом).
  3. Записываем эти данные во временную таблицу SQL.
  4. Выполняем итоговый запрос, связывающий временную таблицу и основные таблицы базы.

Пример реализации на языке 1С 7.7 с использованием ВК 1C++:


// Создаем объект для работы с SQL
ЗапросSQL = СоздатьОбъект("ПоставщикДанных");
// Создаем временную таблицу
ТекстСоздания = "
|CREATE TABLE #TempExternalData (
|    ID_Code CHAR(10),
|    Price NUMERIC(15,2)
|)";
ЗапросSQL.Выполнить(ТекстСоздания);

// Предположим, мы прочитали DBF и подготовили массив данных
// Заполняем временную таблицу
// (Для ускорения лучше использовать параметризованный запрос или вставку блоком)
ТекстВставки = "INSERT INTO #TempExternalData (ID_Code, Price) VALUES (?, ?)";
// ... цикл по данным из DBF ...

После этого мы можем выполнить основной запрос, который свяжет справочник номенклатуры (например, sc84) с нашими данными:


ТекстЗапроса = "
|SELECT
|    Ref.Code as [Код],
|    Ref.Description as [Наименование],
|    Temp.Price as [НоваяЦена]
|FROM
|    sc84 as Ref
|INNER JOIN
|    #TempExternalData as Temp ON Ref.Code = Temp.ID_Code";
Результат = ЗапросSQL.Выполнить(ТекстЗапроса);

Решение 2: Настройка Linked Server (Связанный сервер)

Если нам нужно обращаться к DBF-файлам регулярно, лучшим способом будет настройка Linked Server на стороне SQL Server. Это позволит серверу воспринимать каталог с DBF-файлами как еще одну базу данных.

Проанализируем, как это настроить в SQL Server Management Studio (SSMS):

  1. Перейдите в раздел Server Objects -> Linked Servers.
  2. Создайте новый сервер. В качестве провайдера выберите Microsoft OLE DB Provider for Visual FoxPro.
  3. В поле Data Source укажите полный путь к папке, где лежат ваши DBF.

Теперь в 1С вы можете писать запросы, используя «четырехсоставное» имя таблицы:


ТекстЗапроса = "
|SELECT
|    BaseTable.ID,
|    ExtTable.SomeField
|FROM
|    sc709 AS BaseTable
|INNER JOIN
|    [ИМЯ_СВЯЗАННОГО_СЕРВЕРА]...[имя_dbf_файла] AS ExtTable
|    ON BaseTable.Code = ExtTable.Code";

Важный момент: SQL Server должен иметь права доступа к этой папке. Если папка находится на сетевом ресурсе, служба SQL Server должна быть запущена от имени доменного пользователя с соответствующими правами.

Решение 3: Использование функции OPENROWSET

Если вы не хотите создавать постоянный связанный сервер, можно воспользоваться функцией OPENROWSET, которая позволяет выполнить «разовое» подключение к внешнему источнику. Это часто удобнее для динамически меняющихся путей к файлам.

Разберем пример такого запроса:


ТекстЗапроса = "
|SELECT
|    sql_tab.*,
|    dbf_tab.Price
|FROM
|    sc709 AS sql_tab
|INNER JOIN
|    OPENROWSET('VFPOLEDB', 'C:\ExternalData\'; ' '; ' ', 'SELECT * FROM MyFile.dbf') AS dbf_tab
|    ON sql_tab.Code = dbf_tab.Code";

Чтобы этот код заработал, на SQL Server должна быть разрешена опция Ad Hoc Distributed Queries. Рассмотрим, как её включить через скрипт:


EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'Ad Hoc Distributed Queries', 1;
RECONFIGURE;

Проблема разрядности (x86 vs x64)

Выясним причину еще одной частой ошибки при использовании VFPOLEDB. Провайдер Visual FoxPro существует только в 32-битном варианте. Если ваш SQL Server 64-битный (что является стандартом сегодня), он не сможет использовать 32-битный драйвер напрямую через Linked Server или OPENROWSET.

В такой ситуации у нас есть два пути:

  1. Использовать промежуточный драйвер: Установить 64-битный Microsoft Access Database Engine, который умеет работать с DBF (через ACE OLEDB).
  2. Загрузка через 1С: Сначала прочитать DBF средствами 1С (как в Решении 1), а потом передать данные в SQL. Поскольку сама 1С 7.7 является 32-битным приложением, она успешно создаст соединение с 32-битным VFPOLEDB, а затем передаст данные в 64-битный SQL.

Рекомендации по производительности

При объединении таблиц из разных источников важно помнить о скорости работы. Рассмотрим основные правила:

Подводя итог, можно сказать, что хотя прямое связывание в одном объекте OLEDBCommand невозможно из-за разделения контекстов, инструменты MS SQL Server и внешние компоненты для 1С 7.7 предоставляют достаточно гибких механизмов для решения этой задачи. Выбор конкретного метода зависит от частоты выполнения задачи и архитектуры вашей серверной среды.

← На главную