MS SQL Server + FireBird = Дружба

Источник: delphikingdom
Александр Чмиль

Автор: Александр Чмиль, Королевство Delphi

Недавно столкнулся с проблемой, когда данные из базы данных FireBird (F) нужно было импортировать в базу данных MS SQL Server 2000 (S). Первой мыслью было написать клиента, который бы подключался одновременно к двум БД и в цикле переносил данные из всех таблиц одной базы в другую. Данный подход мне сразу не понравился тем, что пришлось бы писать на Delphi отдельную процедуру импорта данных под каждую таблицу БД - структура и типы данных у них ведь разные. Кроме того, типы данных у этих БД несколько "не стыкуются", так что пришлось бы учитывать и эту особенность при переносе данных.

За советом я обратился к специалистам на Круглом столе Королевства Delphi - вопрос № 71949. Достопочтенный Green в первом же ответе направил меня совершенно в другом направлении: не клиента писать, а подружить эти две СУБД. Полученный результат настолько меня впечатлил, что я решил написать данную статью.

Итак, для того, чтобы иметь возможность делать запросы из (S) к (F), в первую очередь необходимо установить OLE-провайдер, обеспечивающего связь с БД (F). Поиск в Интернете привел на сайт http://www.ibprovider.com, с которого можно скачать бесплатную версию IBProvider. Функционала данной версии вполне достаточно для выполнения задуманного, хотя никто не мешает приобрести платную версию, но нужно ли это в рамках данной задачи?

Следующим шагом будет регистрация IBProvider в системе. Копируем файлы _IBProvider_v3_free_i.dll и cc3250mt.dll в системную папку Windows (например, в c:\windows\system32) и в командной строке выполняем команду:

regsvr32 _IBProvider_v3_free_i.dll

В результате в списке провайдеров появится LCPI.IBProvider.3.Free.

Хочу заметить, что для "дружбы" (S) с (F) в системе должна быть запущена служба MSDTC (Distributed Transaction Coordinator или Координатор Распределенных Транзакций). В моем случае данная служба была отключена и в упорно не желала запускаться (MS Windows 2000). Поиск в Интернете привел к следующему трюку в командной строке:

net stop msdtc (останавливаем службу msdtc)
net start msdtc (запускаем службу)

При наличии прав администратора в списке служб находим "Координатор распределенных транзакций" и устанавливаем тип запуска "авто".

Все. Теперь мы можем работать с БД (F) как из скрипта MS SQL Server, так и через TADOConnection в Delphi, указав в качестве провайдера LCPI.IBProvider.3.Free. Вот пример содержимого строки ADOConnection.ConnectionString:

Provider=LCPI.IBProvider.3.Free;Password=пароль_к_БД;Persist Security Info=True;User ID=логин_к_БД;
Location=D:\Projects\db\DB.FDB;ctype=ASCII;dialect=3;auto_commit=False;
support_odbc_query=False;unicode_mode=False;unicode_stmt=False;dbclient_library=gds32.dll;
dbclient_type=fb

Вернусь к своей задаче - импорт данных в БД MS SQL Server из БД FireBird. Создаем БД (S) по структуре идентичную БД (F). Из-за различий в типах данных этих двух СУБД, в БД (S) создаем столбцы в соответствии с таблицей приведения типов:

Типы данных (F) Типы данных (S)
timestamp datetime
varchar nvarchar
float float или money
smallint (в роли boolean) bit
blob image

Не буду расписывать все соответствия. Их Вы можете определить экспериментально или найти информацию в Интернете.

Перейдем к самому интересному - к "дружбе народов" :

Для получения набора данных из внешней БД, в СУБД (S) имеется функция OpenRowSet, синтаксис которой выглядит так:

OpenRowSet ( 'provider_name' 
    , { 'datasource' ; 'user_id' ; 'password' 
        / 'provider_string' } 
    , { [ catalog. ] [ schema. ] object 
        / 'query' } 
    ) 

Описание функции Вы можете найти в Transact-SQL Reference. В нашем случае эта функция используется с таким набором параметров:

OpenRowSet ('provider_name', 'provider_string', 'query')

В качестве первого параметра указывается имя провайдера (LCPI.IBProvider.3.Free), в качестве второго - строка соединения с БД FireBird, третьего - запрос на выборку данных (select * from TableName).

Для импортирования данных на (S) создаем две ХП:

CREATE PROCEDURE ImportFBTable
 @Table nvarchar(30)
AS
BEGIN
 exec('delete from '+@Table)
 exec('insert into '+@Table+' select * from OpenRowSet(''LCPI.IBProvider.3.Free'','''+
  'Password=пароль_FB;Persist Security Info=True;User ID=логин_FB;'+
  'Location=_путь_к_файлу_БД_FB;ctype=ASCII;dialect=3;'+
  'auto_commit=True;support_odbc_query=False;unicode_mode=False;'+
  'unicode_stmt=False;dbclient_library=gds32.dll;dbclient_type=fb'+
  ''',''select * from '+@Table+''')')

END

CREATE PROCEDURE ImportFBData
AS
BEGIN
 exec ImportFBTable 'Таблица_1'
 exec ImportFBTable 'Таблица_2'
 exec ImportFBTable 'Таблица_3'

 ...
 exec ImportFBTable 'Таблица_N'
END

Выполняем процедуру ImportFBData, которая поочередно вызывает процедуру ImportFBTable, передавая ей в качестве параметра имя импортируемой таблицы (естественно, имена таблиц в (F) и (S) должны быть одинаковыми). Процедура ImportFBTable очищает данные в таблице на (S), получает набор данных из таблицы на (F) и вносит их в таблицу на (S). Конечно, при желании можно "заставить" процедуру не удалять данные, а обновлять, но предоставляю Вам самим создать сие действо - в рамках моей задачи это было не обязательно, так как я не использовал в таблицах на (S) внешние индексы.

Вот, собственно, и вся статья. Возможно, Вас не устроит стиль изложения или Вы заметите некоторые неточности или недомолвки? Тогда предлагаю обсудить это на соответствующей странице.

В заключении хотел сказать, что таким образом можно "подружить" MS SQL Server и с другими БД при наличии соответствующего OLE-провайдера. Например, вот тут вопрос № 71737 рассказывается, как можно получить данные с листа MS Excel.

Также хочу выразить огромную благодарность г-ну Александру Зеленову (aka Green), вовремя направившего меня "на путь истинный" и вдохновившего к написанию данной статьи.


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=21909