2013-04-16 70 views
0

我有一個現有的MySQL數據庫,我嘗試使用以下步驟遷移到PostgreSQL。該數據庫是相當簡單 - 它有幾個外鍵和其他方面的限制,但沒有觸發器,過程等使用DBIx :: Class和PostgreSQL重複索引名稱

  1. 使用DBIx::Class::Schema::Loader從現有的MySQL數據庫生成一組Result類。
  2. 使用Result類來產生一組CREATE TABLE報表PostgreSQL的。
  3. 運行使用psql來設置表(我還沒有得到儘可能數據匯入功能)的CREATE TABLE語句。

我使用的腳本如下(有憑據和數據庫名稱中刪除):

#!/usr/bin/perl 

use Modern::Perl; 
use DBIx::Class::Schema::Loader qw/ make_schema_at /; 

my $dsn = 'dbi:mysql:dbname=database'; 
my $user = ''; 
my $pass = ''; 

make_schema_at(
    'MyDB::Schema', 
    { debug => 1, dump_directory => './lib' }, 
    [ $dsn, $user, $pass 
    ], 
); 

my $schema = MyDB::Schema->connect($dsn, $user, $pass); 
$schema->create_ddl_dir(['PostgreSQL'], '0.1', './', undef, { add_drop_table => 0 }); 

腳本運行成功,並且兩個Result類和.sql文件(包含所有CREATE TABLE聲明)看起來如我所料。

然而,一些表有一個slug列其標記爲在原有的MySQL架構UNIQUE,並導致以下行作爲CREATE TABLE語句的一部分:

"slug" character varying(50) NOT NULL, 
CONSTRAINT "slug" UNIQUE ("slug") 

當我嘗試導入數據(使用psql < tables.sql),我得到每張桌子下面的錯誤有獨特slug柱後的第一個:

NOTICE: CREATE TABLE/UNIQUE will create implicit index "slug" for table "mytable" 
ERROR: relation "slug" already exists 

我的理解是,指數名稱在給定的數據庫中必須是唯一的。我沒有MySQL的這個問題,因爲我只聲明slug VARCHAR(50) NOT NULL UNIQUE而沒有指定索引名稱。

有沒有辦法讓DBIx::Class(或SQL::Translator,其中create_ddl_dir函數使用)在它輸出的數據中生成唯一的索引名稱?我並不特別在乎索引是什麼 - 儘管基於表名的東西是明智的。我瀏覽過文檔,但看不到任何允許這樣的參數。

我可以在導入.sql文件之前手動編輯每個約束,但有超過250個表和很多衝突 - 另外我每次調整遷移過程時都必須這樣做,並且必須重新生成類和SQL。

+0

您是否嘗試過在你的MySQL架構運行'SQL :: Translator'的情況下直接通過'DBIx去::類: :架構:: Loader'? – nwellnhof

+0

同樣的問題 - 它輸出的SQL會導致重複的索引名稱。 – pwaring

+0

看來你在MySQL模式中創建了命名的唯一約束。它應該通過在列定義中簡單使用'UNIQUE'來使用未命名的約束。 – nwellnhof

回答

0

在端的唯一自動化的方式來解決這個問題是與被迫每約束名稱(以及因此的自動索引)由從SQL::Translator解析輸出和附加_$i到每個名稱,其中$i是是唯一的Perl腳本每次看到新的約束時都會增加。

代碼如下 - 假設你會管在STDIN模式:

#!/usr/bin/perl 

use Modern::Perl; 

my $i = 1; 

while (my $line = <>) 
{ 
    if ($line =~ m/CONSTRAINT\s+"([a-zA-Z_]+)"\s+UNIQUE\s+\("([a-zA-Z_]+)"\)/) 
    {  
    my $constraint_name = $1 . '_' . $i; 
    my $column_name = $2; 

    my $replace_str = 'CONSTRAINT "' . $constraint_name . '" UNIQUE ("' . $column_name . '")'; 

    $line =~ s/CONSTRAINT\s+"([a-zA-Z_]+)"\s+UNIQUE\s+\("([a-zA-Z_]+)"\)/$replace_str/; 
    $i++; 
    } 

    print $line; 
}