Часто при интеграции со сторонними системами в 1С 7.7 возникает задача не просто прочитать внешний DBF-файл, а выполнить к нему сложный SQL-запрос (с объединениями, группировками и условиями). Штатный объект XBASE отлично справляется с простым последовательным чтением, но не поддерживает выполнение запросов типа SELECT. Разберем по шагам, как можно реализовать полноценные SQL-запросы к DBF-файлам, используя компоненту 1С++ и технологии ADO/OLEDB.
Рассмотрим подробнее самый популярный и удобный способ работы — использование встроенного в 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-файлы выступают в роли таблиц базы данных. Таким образом, мы легко можем связывать данные из нескольких файлов в одном запросе.
Если по каким-то причинам объект 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, чтобы при чтении строковых данных вместо кириллицы не получить нечитаемые символы.
В 1С++ есть еще один мощный инструмент — класс ODBCRecordset. Он позволяет подключаться к внешним источникам данных через стандартные ODBC-драйверы (например, драйвер Microsoft dBase). Выясним, как это работает:
RS = СоздатьОбъект("ODBCRecordset");УстВнешнийИсточникДанных(СтрокаСоединения).RS.ВыполнитьИнструкцию(ТекстЗапроса, ТЗ);Это очень удобный метод, так как он сохраняет привычный синтаксис 1С++ для прямых запросов.
На практике при чтении DBF через OLEDB можно столкнуться с ошибкой: «Тип переменной не поддерживается» (например, при обращении к objRecordset.Fields(6).Value). Это происходит из-за того, что драйвер не всегда корректно преобразует специфичные числовые форматы DBF (Numeric) во внутренние типы COM/1C.
Разберем два способа решения этой проблемы:
CAST(ИмяПоля as CHAR) в самом SQL-запросе. Текст передастся в 1С как строка, а при необходимости вы сможете преобразовать его в число функцией Число() уже в коде 1С.schema.ini. В нем жестко прописываются типы колонок и их свойства для каждого файла. Это снимает проблему неопределенности типов на уровне драйвера.Часто результат запроса нужно поместить не в обычную ТаблицаЗначений, а в ИндексированнаяТаблица для ускорения дальнейшего поиска. Посмотрим на пример кода:
начало = _GetPerformanceCounter();
ИТЗ = СоздатьОбъект("ИндексированнаяТаблица");
Запрос.ВыполнитьИнструкцию(ТекстЗапроса, ИТЗ);
Сообщить("Время выполнения запроса: " + (_GetPerformanceCounter()-начало));
Важное предупреждение: Метод ВыполнитьИнструкцию корректно работает с ИТЗ только если имена всех возвращаемых колонок уникальны. Если вы пишете запрос вида SELECT a.*, b.* и в обоих файлах есть колонки с одинаковыми именами (например, LIZ), в результирующей таблице возникнет конфликт имен. Из-за этого ИндексированнаяТаблица может оказаться пустой или работать некорректно. Всегда явно задавайте алиасы для пересекающихся полей: SELECT a.LIZ AS LIZ_A, b.LIZ AS LIZ_B.
Проанализируем еще два мощных подхода, если стандартный OLEDB вас не устраивает:
vtable или libspatialite можно подключить DBF-файл как виртуальную таблицу прямо в базу SQLite в оперативной памяти. Это дает огромный прирост скорости при выполнении сложных JOIN-запросов между внешним DBF и выгруженными данными из 1С.SELECT * FROM [LinkedServer]...[File.dbf], объединяя (JOIN) таблицы 1С с данными из файла на стороне сервера СУБД. Это самый производительный вариант для больших объемов данных.