Александр Чмиль дата публикации 15-09-2009 13:15 MS 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
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), вовремя направившего меня "на путь истинный" и вдохновившего к написанию данной статьи.
[MS SQL Server] [Гетерогенные запросы] [FireBird & Yafill]
Обсуждение материала [ 22-06-2010 00:21 ] 5 сообщений |