На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! информация о разделе
user posted imageДанный раздел предназначается исключительно для обсуждения вопросов использования языка запросов SQL. Обсуждение общих вопросов, связанных с тематикой баз данных - обсуждаем в разделе "Базы данных: общие вопросы". Убедительная просьба - соблюдать "Правила форума" и не пренебрегать "Правильным оформлением своих тем". Прежде, чем создавать тему, имеет смысл заглянуть в раздел "Базы данных: FAQ", возможно там уже есть ответ.

Модераторы: Akina
  
> Перенос данных из одной базы данных в другую , Firebird 1.5.3/2.5
    Доброго времени суток!

    Задача стоит такая: мы решили перейти от использования Firebird 1.5 к Firebird 2.5. C преобразованием структуры базы (метаданных) уже разобрались. А вот с данными вышла заминка. В версии 1.5 все строковые (varchar) параметры у нас хранятся в win1251, а нам в 2.5 нужно использовать UTF8. Самым простым решением показалось пересоздать базу из скрипта, указав при создании charset = utf8, а после этого перекопировать данные из старой базы в новую. При этом они в новой базе должны автоматически записаться в utf8. Но с самим копированием не все так просто: ряд таблиц имеет генераторы на первичный ключ, некоторые таблицы имеют взаимосвязь по внешним ключам. Например таблица клиентов и таблица заказов, где в таблице заказов указан ID клиента из таблицы клиентов. И таких связей довольно много.
    Каким способом лучше произвести перенос данных в данном случае?
    Разумеется можно написать на Дельфи, к примеру, приложение, которое будет последовательно читать данные из таблиц и раскладывать их в новую базу согласно взаимосвязей. Но может есть более оптимальный способ? Поделитесь пожалуйста опытом.
      отключить все тригеры , FK перенести данные в любой последовательности и потом все включить обратно.

      Добавлено
      или в IBExpert нажвть "Извлечь методанные" указать что надо извлекать записи в таблицах в результате получите скрипт, выполните его на базе нового формата.
        Спасибо за ответ. Но проблема в том, что это не разовое действие. Переход на 2.5 надо провести у ряда клиентов и потому нужен автоматизированный механизм (чтобы участие самих пользователей в процессе было минимальным).
        Есть такая мысль: воспользоваться утилитой массового копирования данных, а по окончанию выставить скриптом значения генераторов (по количеству записей в таблицах). IBDatapump в этом случае подойдет? Или лучше в сторону каких-то других утилит смотреть?

        Добавлено
        Проверил, IBDatapump не подойдет... он не знает utf8, только unicode_fss. Есть ли какая-то альтернатива для массового копирования?
          Цитата SilverShield @
          а нам в 2.5 нужно использовать UTF8

          а зачем хранить в UTF8?

          вто тут пишут http://www.ibase.ru/unicode_faq.html
          что можно хранить в 1 кодировке а получать и записывать в другой

          например базу оставляешь WIN1251 а получаешь от нее в UTF8

          ps собственно тоже предстоит переход клиентской прогр. на utf8... если не трудно отпишитесь о своих результатах
            Смысл как раз в том, чтобы в базе данных можно было хранить символы, отличные от win1251. Это один из шагов к мультиязычности приложения. Самый подходящий вариант - UTF8. А вот при чтении из базы, можно читать в той же win1251 (в смысле при коннекте чарсет задать), если приложение юникод не держит.
            Буду сейчас методы копирования данных искать...
            Пока нашел на sql.ru про копирование через block (копирование данных. см. самый низ страницы). Не знаю правда может ли это помочь при копировании данных в разных чарсетах.
              Используй IBEScript/IBEBlock
              Как раз подходит. Только скрипт надо правильно формировать.
                Romkin, спасибо за совет. IBEBlock действительно неплохое решение по копированию данных, но не могу никак добиться с его помощью копирования данных из одного чарсета в другой.
                Скрипт написал так:
                ExpandedWrap disabled
                  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 !
                Подскажите плиз, как правильно произвести конвертирование?
                  Так при соединении utf8 или 1251 все должно перевестись автоматом вроде. То есть соединяешься с БД, в которой utf8 указывая 1251 для соединения. Оно должно перевести.
                    Я тоже на это расчитывал. Собственно так оно и происходит обычно. Но при выполнении указанного скрипта это не произошло (смотрю по тексту ошибки).
                      Цитата SilverShield @
                      names=UTF8;

                      А это что? В Dest - тоже 1251 поставь
                        Да, мой промах. Надо к юникодной базе тоже в win1251 коннектится. Сконвертируется оно само по чарсету базы. Спасибо!
                        Можешь еще подсказать, как прочитать в IBEBlock действующее значение генератора в базе?
                          Цитата SilverShield @
                          как прочитать в IBEBlock действующее значение генератора в базе?

                          Где угодно значение генератора читается запросом
                          ExpandedWrap disabled
                            select GEN_ID(<gen name>, 0) from rdb$database;

                          :)
                            Спасибо :) Теперь осталось с установкой значения генератора в новой базе разобраться... Код вышел такой:
                            ExpandedWrap disabled
                              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
                              Цитата SilverShield @
                              PS: вариант GEN_ID(GEN_CustNo_ID, :tgid); тоже пробовал... все тот же Parsing error

                              select GEN_ID(GEN_CustNo_ID, :tgid) from rdb$database?
                                к сожалению все тоже самое: Parsing error
                                Такой вариант тоже не отработал.
                                  Цитата SilverShield @
                                  к сожалению все тоже самое: Parsing error
                                  Такой вариант тоже не отработал.

                                  Ты уверен что правильно пишешь скрипт?
                                    Вот код скрипта целиком:
                                    ExpandedWrap disabled
                                      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
                                    Пробовал записывать для эксперимента не значение переменной, а конкретную цифру - результат тот же (ошибка).
                                    Сообщение отредактировано: SilverShield -
                                      ExpandedWrap disabled
                                        select GEN_ID(GEN_CONTROLLERS_ID, :tgid) from rdb$database;

                                      замени на
                                      ExpandedWrap disabled
                                        select GEN_ID(GEN_CONTROLLERS_ID, :tgid) from rdb$database into :tgid;

                                      или лучше просто
                                      ExpandedWrap disabled
                                        tgid = GEN_ID(GEN_CONTROLLERS_ID, :tgid);

                                      Ты в скрипте.
                                        Цитата Romkin @
                                        tgid = GEN_ID(GEN_CONTROLLERS_ID, :tgid);

                                        Супер!! Так работает! Большое спасибо!
                                        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                        0 пользователей:


                                        Рейтинг@Mail.ru
                                        [ Script execution time: 0,0435 ]   [ 15 queries used ]   [ Generated: 4.03.25, 21:13 GMT ]