
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.118.149.94] |
![]() |
|
![]() | Данный раздел предназначается исключительно для обсуждения вопросов использования языка запросов SQL. Обсуждение общих вопросов, связанных с тематикой баз данных - обсуждаем в разделе "Базы данных: общие вопросы". Убедительная просьба - соблюдать "Правила форума" и не пренебрегать "Правильным оформлением своих тем". Прежде, чем создавать тему, имеет смысл заглянуть в раздел "Базы данных: FAQ", возможно там уже есть ответ. |
Сообщ.
#1
,
|
|
|
Доброго времени суток!
Задача стоит такая: мы решили перейти от использования Firebird 1.5 к Firebird 2.5. C преобразованием структуры базы (метаданных) уже разобрались. А вот с данными вышла заминка. В версии 1.5 все строковые (varchar) параметры у нас хранятся в win1251, а нам в 2.5 нужно использовать UTF8. Самым простым решением показалось пересоздать базу из скрипта, указав при создании charset = utf8, а после этого перекопировать данные из старой базы в новую. При этом они в новой базе должны автоматически записаться в utf8. Но с самим копированием не все так просто: ряд таблиц имеет генераторы на первичный ключ, некоторые таблицы имеют взаимосвязь по внешним ключам. Например таблица клиентов и таблица заказов, где в таблице заказов указан ID клиента из таблицы клиентов. И таких связей довольно много. Каким способом лучше произвести перенос данных в данном случае? Разумеется можно написать на Дельфи, к примеру, приложение, которое будет последовательно читать данные из таблиц и раскладывать их в новую базу согласно взаимосвязей. Но может есть более оптимальный способ? Поделитесь пожалуйста опытом. |
Сообщ.
#2
,
|
|
|
отключить все тригеры , FK перенести данные в любой последовательности и потом все включить обратно.
Добавлено или в IBExpert нажвть "Извлечь методанные" указать что надо извлекать записи в таблицах в результате получите скрипт, выполните его на базе нового формата. |
Сообщ.
#3
,
|
|
|
Спасибо за ответ. Но проблема в том, что это не разовое действие. Переход на 2.5 надо провести у ряда клиентов и потому нужен автоматизированный механизм (чтобы участие самих пользователей в процессе было минимальным).
Есть такая мысль: воспользоваться утилитой массового копирования данных, а по окончанию выставить скриптом значения генераторов (по количеству записей в таблицах). IBDatapump в этом случае подойдет? Или лучше в сторону каких-то других утилит смотреть? Добавлено Проверил, IBDatapump не подойдет... он не знает utf8, только unicode_fss. Есть ли какая-то альтернатива для массового копирования? |
Сообщ.
#4
,
|
|
|
Цитата SilverShield @ а нам в 2.5 нужно использовать UTF8 а зачем хранить в UTF8? вто тут пишут http://www.ibase.ru/unicode_faq.html что можно хранить в 1 кодировке а получать и записывать в другой например базу оставляешь WIN1251 а получаешь от нее в UTF8 ps собственно тоже предстоит переход клиентской прогр. на utf8... если не трудно отпишитесь о своих результатах |
Сообщ.
#5
,
|
|
|
Смысл как раз в том, чтобы в базе данных можно было хранить символы, отличные от win1251. Это один из шагов к мультиязычности приложения. Самый подходящий вариант - UTF8. А вот при чтении из базы, можно читать в той же win1251 (в смысле при коннекте чарсет задать), если приложение юникод не держит.
Буду сейчас методы копирования данных искать... Пока нашел на sql.ru про копирование через block (копирование данных. см. самый низ страницы). Не знаю правда может ли это помочь при копировании данных в разных чарсетах. |
Сообщ.
#6
,
|
|
|
Используй IBEScript/IBEBlock
Как раз подходит. Только скрипт надо правильно формировать. |
Сообщ.
#7
,
|
|
|
Romkin, спасибо за совет. IBEBlock действительно неплохое решение по копированию данных, но не могу никак добиться с его помощью копирования данных из одного чарсета в другой.
Скрипт написал так: ![]() ![]() execute ibeblock as begin FBSrc = ibec_CreateConnection(__ctFirebird,'DBName="localhost:C:\DB1.FDB"; ClientLib=C:\Program Files\Firebird\Bin\fbclient.dll; user=SYSDBA; password=masterkey; names=WIN1251; sqldialect=3'); FBDest = ibec_CreateConnection(__ctFirebird,'DBName="localhost:C:\DB2.FDB"; ClientLib=C:\Program Files\Firebird\Bin\fbclient.dll; user=SYSDBA; password=masterkey; names=UTF8; sqldialect=3'); ibec_UseConnection(FbSrc); for select CustNo, Company, Addr1 from customer order by company into :CustNo, :Company, :Addr1 do begin use FBDest; INSERT INTO CUSTOMER (CustNo, Company, Addr1) VALUES (:CustNo, :Company, :Addr1); use FBSrc; end use FBDest; COMMIT; ibec_CloseConnection(FBSrc); ibec_CloseConnection(FBDest); end При этом имею ошибку "Incompatible column/host variable data type error code = -303 Malformed string". Т.е. похоже ошибка возникла при записи значений в win1251 в utf8. Если и там и там при подключении поставить win1251, то копирование проходит успешно. Но мне надо именно значения из базы в чарсете 1251 перегнать в UTF8 ! Подскажите плиз, как правильно произвести конвертирование? |
Сообщ.
#8
,
|
|
|
Так при соединении utf8 или 1251 все должно перевестись автоматом вроде. То есть соединяешься с БД, в которой utf8 указывая 1251 для соединения. Оно должно перевести.
|
Сообщ.
#9
,
|
|
|
Я тоже на это расчитывал. Собственно так оно и происходит обычно. Но при выполнении указанного скрипта это не произошло (смотрю по тексту ошибки).
|
Сообщ.
#10
,
|
|
|
Цитата SilverShield @ names=UTF8; А это что? В Dest - тоже 1251 поставь |
Сообщ.
#11
,
|
|
|
Да, мой промах. Надо к юникодной базе тоже в win1251 коннектится. Сконвертируется оно само по чарсету базы. Спасибо!
Можешь еще подсказать, как прочитать в IBEBlock действующее значение генератора в базе? |
Сообщ.
#12
,
|
|
|
Цитата SilverShield @ как прочитать в IBEBlock действующее значение генератора в базе? Где угодно значение генератора читается запросом ![]() ![]() select GEN_ID(<gen name>, 0) from rdb$database; ![]() |
Сообщ.
#13
,
|
|
|
Спасибо
![]() ![]() ![]() use FBSrc; tgid = GEN_ID(GEN_CustNo_ID, 0); -- from rdb$database; use FBDest; ALTER SEQUENCE GEN_CustNo_ID RESTART WITH :tgid; --SET GENERATOR GEN_CustNo_ID TO :tgid; COMMIT; ibec_CloseConnection(FBSrc); ibec_CloseConnection(FBDest); end Получение значения генератора проходит, а вот на запись выдается Parsing error. Раньше код установки генератора был SET GENERATOR имя TO значение. С версии 2.х он судя по всему изменился (со старым вариантом было сказано feature not supported). Новый вариант подсказал IBExpert в DDL генератора. Но и с ним ошибка. ( PS: вариант GEN_ID(GEN_CustNo_ID, :tgid); тоже пробовал... все тот же Parsing error |
Сообщ.
#14
,
|
|
|
Цитата SilverShield @ PS: вариант GEN_ID(GEN_CustNo_ID, :tgid); тоже пробовал... все тот же Parsing error select GEN_ID(GEN_CustNo_ID, :tgid) from rdb$database? |
Сообщ.
#15
,
|
|
|
к сожалению все тоже самое: Parsing error
Такой вариант тоже не отработал. |
Сообщ.
#16
,
|
|
|
Цитата SilverShield @ к сожалению все тоже самое: Parsing error Такой вариант тоже не отработал. Ты уверен что правильно пишешь скрипт? |
Сообщ.
#17
,
|
|
|
Вот код скрипта целиком:
![]() ![]() execute ibeblock as -- declare variable TGID integer; begin FBSrc = ibec_CreateConnection(__ctFirebird,'DBName="192.168.1.1:C:\DB\DB1.GDB"; ClientLib=C:\Program Files\Firebird\Firebird_2_5\bin\fbclient.dll; user=SYSDBA; password=masterkey; names=WIN1251; sqldialect=3'); FBDest = ibec_CreateConnection(__ctFirebird,'DBName="192.168.1.1:C:\DB\DB2.GDB"; ClientLib=C:\Program Files\Firebird\Firebird_2_5\bin\fbclient.dll; user=SYSDBA; password=masterkey; names=WIN1251; sqldialect=3'); ibec_UseConnection(FbSrc); for select id, mail, icq, stat from controllers order by id into :id, :mail, :icq, :stat do begin use FBDest; insert into controllers(id, mail, icq, stat) values (:id, :mail, :icq, :stat); use FBSrc; end use FBDest; use FBSrc; tgid = GEN_ID(GEN_CONTROLLERS_ID, 0); -- from rdb$database; use FBDest; select GEN_ID(GEN_CONTROLLERS_ID, :tgid) from rdb$database; COMMIT; ibec_CloseConnection(FBSrc); ibec_CloseConnection(FBDest); end Скрипт сохранил в файл script.sql и выполняю его так: IBEScript script.sql -N -E Если закоментировать строку установки значения генератора select GEN_ID(GEN_CONTROLLERS_ID, :tgid) from rdb$database; то скрипт выполняется без ошибок. Если возвращаю обратно - Parsing error At line 24 column 64 Пробовал записывать для эксперимента не значение переменной, а конкретную цифру - результат тот же (ошибка). |
Сообщ.
#18
,
|
|
|
![]() ![]() select GEN_ID(GEN_CONTROLLERS_ID, :tgid) from rdb$database; замени на ![]() ![]() select GEN_ID(GEN_CONTROLLERS_ID, :tgid) from rdb$database into :tgid; или лучше просто ![]() ![]() tgid = GEN_ID(GEN_CONTROLLERS_ID, :tgid); Ты в скрипте. |
Сообщ.
#19
,
|
|
|
Цитата Romkin @ tgid = GEN_ID(GEN_CONTROLLERS_ID, :tgid); Супер!! Так работает! Большое спасибо! |