Версия для печати
MS SQL Server + FireBird = Дружба
http://www.delphikingdom.com/asp/viewitem.asp?catalogID=1412Александр Чмиль
дата публикации 15-09-2009 13:15MS SQL Server + FireBird = Дружба Недавно столкнулся с проблемой, когда данные из базы данных 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), вовремя направившего меня "на путь истинный" и вдохновившего к написанию данной статьи.