Как выполнять SQL-запросы к внешним DBF-файлам в 1С 7.7 с помощью 1С++?

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

Часто при интеграции со сторонними системами в 1С 7.7 возникает задача не просто прочитать внешний DBF-файл, а выполнить к нему сложный SQL-запрос (с объединениями, группировками и условиями). Штатный объект XBASE отлично справляется с простым последовательным чтением, но не поддерживает выполнение запросов типа SELECT. Разберем по шагам, как можно реализовать полноценные SQL-запросы к DBF-файлам, используя компоненту 1С++ и технологии ADO/OLEDB.

Использование объекта OLEDBData в 1С++

Рассмотрим подробнее самый популярный и удобный способ работы — использование встроенного в 1С++ класса OLEDBData совместно с провайдером Visual FoxPro OLE DB (VFPOLEDB). Этот подход позволяет писать прямые запросы к папке с DBF-файлами как к базе данных и сразу выгружать результат в Таблицу Значений.

Проанализируем пример кода подключения и выполнения запроса:


База = СоздатьОбъект("OLEDBData");
Соединение ="
|Provider=VFPOLEDB.1;
|Data Source=E:\TEMPO\; // Указываем путь к каталогу с DBF файлами
|Mode=Read;
|";
Рез = База.Соединение(Соединение);
Запрос = База.СоздатьКоманду();

ТекстЗапроса = "SELECT a.*, b.* FROM [pp.dbf] AS a INNER JOIN [lg.dbf] AS b ON a.LIZ=b.LIZ";
ТЗ = Запрос.ВыполнитьИнструкцию(ТекстЗапроса);

В этом примере Data Source указывает на директорию. Сами DBF-файлы выступают в роли таблиц базы данных. Таким образом, мы легко можем связывать данные из нескольких файлов в одном запросе.

Работа через классический ADODB.Connection

Если по каким-то причинам объект OLEDBData не подходит, мы можем использовать стандартный COM-объект ADODB.Connection. Посмотрим на пример инициализации соединения:


DBConn = CreateObject("ADODB.Connection");
DBConn.Open("Provider=vfpoledb;" + 
            "Data Source=E:\TEMPO\;" + 
            "Mode=ReadWrite|Share Deny None;" + 
            "Collating Sequence=MACHINE;" + 
            "Password='';");

Важный нюанс с кодировками: Внешние DBF часто бывают в DOS-кодировке (CP866), тогда как 1С 7.7 работает в Windows-кодировке (CP1251). При использовании VFPOLEDB обязательно обращайте внимание на кодировку. В строку соединения можно добавить параметр CodePage=866 или CodePage=1251, чтобы при чтении строковых данных вместо кириллицы не получить нечитаемые символы.

Использование класса ODBCRecordset

В 1С++ есть еще один мощный инструмент — класс ODBCRecordset. Он позволяет подключаться к внешним источникам данных через стандартные ODBC-драйверы (например, драйвер Microsoft dBase). Выясним, как это работает:

  1. Создаем объект: RS = СоздатьОбъект("ODBCRecordset");
  2. Переключаем контекст на внешнюю базу методом УстВнешнийИсточникДанных(СтрокаСоединения).
  3. Выполняем запрос: RS.ВыполнитьИнструкцию(ТекстЗапроса, ТЗ);

Это очень удобный метод, так как он сохраняет привычный синтаксис 1С++ для прямых запросов.

Решение проблемы с чтением числовых полей (Numeric)

На практике при чтении DBF через OLEDB можно столкнуться с ошибкой: «Тип переменной не поддерживается» (например, при обращении к objRecordset.Fields(6).Value). Это происходит из-за того, что драйвер не всегда корректно преобразует специфичные числовые форматы DBF (Numeric) во внутренние типы COM/1C.

Разберем два способа решения этой проблемы:

  1. Преобразование в запросе: Используйте конструкцию CAST(ИмяПоля as CHAR) в самом SQL-запросе. Текст передастся в 1С как строка, а при необходимости вы сможете преобразовать его в число функцией Число() уже в коде 1С.
  2. Использование файла schema.ini: Если вы используете провайдер Microsoft Jet или текстовые драйверы ODBC, в каталоге с DBF-файлами можно создать файл schema.ini. В нем жестко прописываются типы колонок и их свойства для каждого файла. Это снимает проблему неопределенности типов на уровне драйвера.

Выгрузка результата в Индексированную Таблицу (ИТЗ)

Часто результат запроса нужно поместить не в обычную ТаблицаЗначений, а в ИндексированнаяТаблица для ускорения дальнейшего поиска. Посмотрим на пример кода:


начало = _GetPerformanceCounter();
ИТЗ = СоздатьОбъект("ИндексированнаяТаблица");
Запрос.ВыполнитьИнструкцию(ТекстЗапроса, ИТЗ);
Сообщить("Время выполнения запроса: " + (_GetPerformanceCounter()-начало));

Важное предупреждение: Метод ВыполнитьИнструкцию корректно работает с ИТЗ только если имена всех возвращаемых колонок уникальны. Если вы пишете запрос вида SELECT a.*, b.* и в обоих файлах есть колонки с одинаковыми именами (например, LIZ), в результирующей таблице возникнет конфликт имен. Из-за этого ИндексированнаяТаблица может оказаться пустой или работать некорректно. Всегда явно задавайте алиасы для пересекающихся полей: SELECT a.LIZ AS LIZ_A, b.LIZ AS LIZ_B.

Альтернативные продвинутые методы: 1sqlite и Linked Servers

Проанализируем еще два мощных подхода, если стандартный OLEDB вас не устраивает:

  1. Использование 1sqlite с виртуальными таблицами: С помощью расширения vtable или libspatialite можно подключить DBF-файл как виртуальную таблицу прямо в базу SQLite в оперативной памяти. Это дает огромный прирост скорости при выполнении сложных JOIN-запросов между внешним DBF и выгруженными данными из 1С.
  2. MS SQL Linked Server: Если ваша база 1С 7.7 крутится на SQL Server, внешние DBF можно подключить прямо в SQL Server как Linked Server (связанный сервер). В этом случае вы сможете прямо из 1С++ писать запросы вида SELECT * FROM [LinkedServer]...[File.dbf], объединяя (JOIN) таблицы 1С с данными из файла на стороне сервера СУБД. Это самый производительный вариант для больших объемов данных.
← На главную