異なるDBMS間のSQLを変換してくれるモジュール SQL::Translator

こういうの無かったらつくってみようかなーと思ったんですが、やっぱりありましたね。

テスト用で使ったsql文(oracle)

CREATE TABLE EMP
(EMPNO NUMBER(4) NOT NULL,
     ENAME VARCHAR2(10),
     JOB VARCHAR2(9),
     MGR NUMBER(4),
     HIREDATE DATE,
     SAL NUMBER(7, 2),
     COMM NUMBER(7, 2),
     DEPTNO NUMBER(2),
     CONSTRAINT PK_EMP PRIMARY KEY(EMPNO),
     CONSTRAINT FK_DEPTNO FOREIGN KEY (DEPTNO) REFERENCES DEPT
);

CREATE TABLE DEPT
(DEPTNO NUMBER(2),
     DNAME VARCHAR2(14),
     LOC VARCHAR2(13),
     CONSTRAINT PK_DEPT PRIMARY KEY(DEPTNO)
);

異なるDBMS間でSQL文の変換

こんな感じで簡単にSQL文の変換をしてくれます

use SQL::Translator;

my $translator = SQL::Translator->new;
my $output     = $translator->translate(
    from       => 'Oracle',
    to         => 'MySQL',
    # Or an arrayref of filenames, i.e. [ $file1, $file2, $file3 ]
    filename   => "oracle.sql",
) or die $translator->error;

print $output;

専用コマンドもあり。
こちらも上記と同じ動作です。

sqlt -f Oracle -t MySQL oracle.sql

SQLの差分SQL文出力

さっきMySQL用に出力したSQL文をコピペし、ちょっと改変。
差分は以下のような感じ。*1

$ diff mysql.sql mysql_mod.sql 
17d16
<   `COMM` double(7, 2),
29c28,29
<   `LOC` varchar(13),
---
>   `LOC` text,
>   `POC` varchar(26),
32a33,41
> --
> -- Table: `DEPT`
> --
> CREATE TABLE `HOGE` (
>   `HOGENO` int(2) NOT NULL,
>   `HOGENAME` varchar(14),
>   PRIMARY KEY (`HOGENO`)
> ) ENGINE=InnoDB;


ほんで、SQL::Translator::Diffを使うと
差分を変更するようなSQL文を出力してくれる。
一度 SQL::Translator::Schema に変換してからDiffするらしい。

use SQL::Translator;
use SQL::Translator::Diff;

my $dbms = "MySQL";

my $options_hash = {
    #... 
};
my $diffsql = SQL::Translator::Diff::schema_diff(
    get_tr_schema('mysql.sql'),
    $dbms, 
    get_tr_schema('mysql_mod.sql'),
    $dbms, 
    $options_hash
);
print $diffsql;

sub get_tr_schema {
    my $file = shift;
    my $tr = SQL::Translator->new();
    $tr->parser( $dbms ) or die $tr->error;
    my $out = $tr->translate( $file ) or die $tr->error;
    my $schema = $tr->schema;
    unless ( $schema->name ) {
        $schema->name( $file );
    }
    $schema;
}


これも専用コマンドあります。

sqlt-diff mysql.sql=MySQL mysql_mod.sql=MySQL


出力した結果はこんな感じ。
create文やalter文をダーっと作ってくれます。

-- Convert schema 'mysql.sql' to 'mysql_mod.sql':;

BEGIN;

SET foreign_key_checks=0;

CREATE TABLE `HOGE` (
  HOGENO integer(2) NOT NULL,
  HOGENAME varchar(14),
  PRIMARY KEY (HOGENO)
) ENGINE=InnoDB;

SET foreign_key_checks=1;

ALTER TABLE DEPT ADD COLUMN POC varchar(26),
                 CHANGE COLUMN LOC LOC text;

ALTER TABLE EMP DROP COLUMN COMM;

COMMIT;

cgiまで

webアプリとして表示できるcgiまでついてます!
http://cpansearch.perl.org/src/RIBASUSHI/SQL-Translator-0.11006/script/sqlt.cgi
モジュールインストールしてcgiファイルだけ置けば使えてしまいます。これは便利。
デモ用で個人用のサーバに置いてみましたよ
http://toritori0318.sakura.ne.jp/sqlt.cgi



感想

実はDBMSだけでなくExcelやらXMLやらHTMLやらグラフやらいろんなものに変換できます。
簡単なリレーション図なんかもcgiから出せてしまいますよ。
対応してるDB/フォーマットはここを眺めているとわかるかも。
http://search.cpan.org/~ribasushi/SQL-Translator/
とても便利なモジュールだと思うんですが、あまり情報がないのは何で?


*1:厳密には、変換時にForeignKeyに勝手に付いてしまう「INDEX」文も削除しています。これがあるとSQL::Translator::Diff時にエラーになってしまったので