創薬系で使っているソフトで古いタイプはCSVで出力するものが結構多いので、CSVをDBIで扱うためのモジュールDBD::CSVとDBD::AnyData を触ってみた。DBD::CSVはCSVをSQL::Statementで扱えるようにするモジュールで、DBD::AnyDataはもう少し広くXMLとか/etc/passwdとかのほかのフォーマットも扱えるらしい。
サンプルとして以下のカンマ区切りのファイルを用意する。ちなみにヨコゼキに義侠の慶が入荷したらしい。あー飲んでみたい。
Name,Category,Loc,Vol
群馬泉,純米,群馬,1800
義侠,純米,愛知,720
飛露喜,純米,福島,720
國香,吟醸,静岡,1800
喜久酔,純米,静岡,720
ポイントは両方とも$dbhでテーブル名とカラム名を与えること。区切り文字とか改行文字も指定する。カラム名を明示的に指定しないといわゆるヘッダーがカラム名となる(DBD::CSV,DBD::AnyDataともに)
そこまでやれば、普通にSQLを実行だ。
#!/usr/bin/perl use strict; use warnings; use DBI; my $dbh = DBI->connect("DBI:CSV:csv_eol=\n;csv_sep_char=,"); $dbh->{'csv_tables'}->{'out'} = { 'file' => 'sample_j.csv', }; my $sth = $dbh->prepare(q/SELECT * FROM out where Category = '純米'/); $sth->execute(); while(my $t = $sth->fetchrow_arrayref){ print join(":",@$t),"\n"; } $sth->finish; $dbh->disconnect;
上の例はアレイのリファレンスだが、ハッシュのリファレンスも可能。その場合はヘッダ名でアクセスできる。
#!/usr/bin/perl use strict; use warnings; use DBI; my $dbh = DBI->connect('dbi:AnyData:'); $dbh->func('test','CSV','sample_j.csv','ad_catalog'); my $sth = $dbh->prepare(q/select * from test where Category = '純米'/); $sth->execute() or die "execute: " . $dbh->errorstr(); while(my $t = $sth->fetchrow_hashref){ print $t->{Name},":",$t->{Loc},"\n"; } $sth->finish; $dbh->disconnect;
DBD::AnyData(Version: 0.08)では実行すると以下のエラーが出てちょっと気持ち悪い。
Service description 'file:' can't be loaded: 404 File `' does not exist
DBD::CSVとDBD::AnyDataどっち使うかは$dbhをどう指定するかの部分だけの好みなんだろうけど、CSV扱うという部分に関してはDBD::CSVのほうがわかりやすくて好き。もう少し複雑な書式のデータはDBD::AnyDataのほうがいいのかもしれないが、DBD::AnyDataの/etc/passwdのサンプルぐらいしか試してないので、本当のところはわからん。
DBD::CSVもClass::DBIで扱えるらしい(ナイス!)