PostgreSQLでの部分データ移行

開発環境から本番環境へデータベースを移行する場合など、PostgreSQL では pg_dump でダンプし psql で読み込む(pg_dumpのダンプファイルは SQL文なので、正確には実行)という事を行うと思います。

移行するデータが全体なら pg_dump、 テーブル単位なら pg_dump -t TABLE でダンプできますが、
「あるテーブルのある条件にあてはまるものだけ」という場合は pg_dump では出来ません。

こんな時、PostgreSQL がバージョン8以降なら COPY 文の query 指定が便利です。

SQL> COPY  (SELECT * FROM sample_table WHERE id > 10000) TO '/tmp/sample_dump'; 

のようなSQLを実行すると /tmp/sample_dump に 条件に合ったデータが書かれるので、エディターやスクリプト言語
先頭に

COPY "sample_table" FROM stdin;

終わりに

\.

を追加すれば、psql で読み込めるようになります。


しかし、 PostgreSQL 7.X では COPY 文の query 指定が出来ないので 簡単なプログラムを書いてみました。
諸事情で Perl です。

use strict;
use Pg;

my $table = "sample_table";
my $cond = "id > 10000";

my $db = Pg::connectdb("dbname=sample_db user=sample_user");
die "Can't connect to DB " . $db->errorMessage  unless ($db->status == PGRES_CONNECTION_OK);

my $result = $db->exec("select * from $table where $cond");
die "Select error " . $db->errorMessage  unless ($result->resultStatus == PGRES_TUPLES_OK);

print "COPY \"$table\" FROM stdin;\n";
while (my @row = $result->fetchrow) {
    print join("\t", map{defined($_) ? $_ : '\N'} @row) . "\n";
}
print "\\.\n";

COPY文のデータ形式は NULL を \N で表すところが特殊なくらいで、あとは文字列としてみた値をタブ区切りで並べれば良いので PostgreSQL の外部形式(?) としては 扱い易いと思います :-)


.