При работе в среде 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-файл, лежащий в произвольной папке на клиентском компьютере, без специальных настроек.
Рассмотрим подход, предложенный в обсуждении: предварительную загрузку данных во временную таблицу SQL. Это самый надежный метод, так как после загрузки данных обе таблицы (бывшая DBF и штатная SQL) оказываются в одном контексте, и мы можем использовать всю мощь JOIN.
Разберем процесс по шагам:
Пример реализации на языке 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.Выполнить(ТекстЗапроса);
Если нам нужно обращаться к DBF-файлам регулярно, лучшим способом будет настройка Linked Server на стороне SQL Server. Это позволит серверу воспринимать каталог с DBF-файлами как еще одну базу данных.
Проанализируем, как это настроить в SQL Server Management Studio (SSMS):
Microsoft OLE DB Provider for Visual FoxPro.Теперь в 1С вы можете писать запросы, используя «четырехсоставное» имя таблицы:
ТекстЗапроса = "
|SELECT
| BaseTable.ID,
| ExtTable.SomeField
|FROM
| sc709 AS BaseTable
|INNER JOIN
| [ИМЯ_СВЯЗАННОГО_СЕРВЕРА]...[имя_dbf_файла] AS ExtTable
| ON BaseTable.Code = ExtTable.Code";
Важный момент: SQL Server должен иметь права доступа к этой папке. Если папка находится на сетевом ресурсе, служба SQL Server должна быть запущена от имени доменного пользователя с соответствующими правами.
Если вы не хотите создавать постоянный связанный сервер, можно воспользоваться функцией 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;
Выясним причину еще одной частой ошибки при использовании VFPOLEDB. Провайдер Visual FoxPro существует только в 32-битном варианте. Если ваш SQL Server 64-битный (что является стандартом сегодня), он не сможет использовать 32-битный драйвер напрямую через Linked Server или OPENROWSET.
В такой ситуации у нас есть два пути:
Microsoft Access Database Engine, который умеет работать с DBF (через ACE OLEDB).VFPOLEDB, а затем передаст данные в 64-битный SQL.При объединении таблиц из разных источников важно помнить о скорости работы. Рассмотрим основные правила:
JOIN). Это в разы ускорит выполнение запроса.OPENROWSET может работать медленно, так как SQL Server придется выкачивать файл целиком во временное хранилище. В этом случае лучше доверить загрузку специализированным ETL-инструментам или использовать Bulk Insert.Подводя итог, можно сказать, что хотя прямое связывание в одном объекте OLEDBCommand невозможно из-за разделения контекстов, инструменты MS SQL Server и внешние компоненты для 1С 7.7 предоставляют достаточно гибких механизмов для решения этой задачи. Выбор конкретного метода зависит от частоты выполнения задачи и архитектуры вашей серверной среды.