OracleのSQL出力をMysqlライクに
対話式武藤 - マツモブログ
対話式+Text::ASCIITable あぁ、うんこれは便利そうということで、SQLを投げるやつ作ってみた。
作った背景として、sqlplusの結果がぐちゃっとしてて見辛いという理由から。
現在、Oracle ClientやMS Exchangeその他GUIが使えない環境で、sshでOracleサーバに接続して、sqlplusコマンド打って、SQL文を直接叩く。という地味な作業やっております。
環境や設定にも因るとは思うのですが、次のテーブルにsqlplusを投げるとこんな感じ
M_USER | ||||
ID | NAME | REG_DATE | UPD_DATE | DEL_FLG |
1 | HOGE | 2007-01-01 00:00:00 | 2007-04-01 12:00:00 | 1 |
2 | FUGA | 2007-03-07 17:54:33 | 2007-03-07 17:54:33 | 0 |
select * from M_USER; ID NAME REG_DATE ---------- ------------------------------ ------------------- UPD_DATE DEL_FLG ------------------- ------- 1 HOGE 2007-01-01 00:00:00 2007-04-01 12:00:00 1 2 FUGA 2007-03-07 17:54:33 2007-03-07 17:54:33 0
別に慣れれば平気なのかも知れんが、mysqlだとこう。
+----+------+---------------------+---------------------+---------+ | ID | NAME | REG_DATE | UPD_DATE | DEL_FLG | +----+------+---------------------+---------------------+---------+ | 1 | HOGE | 2007-01-01 00:00:00 | 2007-04-01 12:00:00 | 1 | | 2 | FUGA | 2007-03-07 17:54:33 | 2007-03-07 17:54:33 | 0 | +----+------+---------------------+---------------------+---------+
どっちが見易いかって、そりゃ後者だ。(ワシだけか?)
select ID||','||NAME||','||REG_DATE||','||……… なselect句にして回避していたが、これも縦位置が揃わない。
ということで、対話式SQL&整形ツールをトラバ元参照に作った。
use strict; use warnings; use DBI; use Term::ReadLine; use Text::ASCIITable; my $output = "./.sqlhistory"; open (my $fh,">>$output"); my $term = Term::ReadLine->new('SQL'); my $prompt = "SQL : "; my $OUT = $term->OUT || *STDOUT; $ENV{ORACLE_HOME}=q|/path/to/oracle_home/|; $ENV{NLS_LANG} = q|American_Japan.JA16SJIS|; our $dbh = DBI::connect('dbi:Oracle',user,password); our $sql = ""; while (defined(my $in = $term->readline($prompt))) { if(!defined $in or $in eq ''){ next; }elsif ($in eq 'exit' or $in eq 'quit') { $dbh->disconnect(); print "Bye!!\n"; last; }else{ if($in !~ m/;$/){ $sql .= "$in\n"; next; }else{ $in =~ s/;$//; $sql .= $in; } my ($result) = sqlexec($dbh,$sql); $sql =""; if(!defined $result->[0] or $result->[0] ==0){ print "SQL Error => $result->[1]\n"; }else{ my $header = $result->[1]; my $data_ref = $result->[2]; my $t = Text::ASCIITable->new(); $t->setCols(@$header); for my $line_ref (@$data_ref) { my @row = (); for my $key(@$header){ push @row,$line_ref->{$key} } $t->addRow(@row); } print $t; print $fh "$sql\n"; print $fh $t; } } $term->addhistory($_) if /\S/; } close $fh; sub sqlexec{ my $dbh = shift; my $sql_data = shift; my $sth = $dbh->prepare($sql_data) or return [0,$dbh->err.":".$dbh->errstr]; $sth->execute() or return[0,$sth->err.":".$sth->errstr]; my @tbl_header = (); my @line_result = (); for (0..$sth->{NUM_OF_FIELDS}-1){ push @tbl_header,$sth->{NAME}->[$_]; } while(my $data_ref = $sth->fetchrow_hashref()){ push @line_result,$data_ref; } return [1,\@tbl_header,\@line_result]; }
結果はこんな感じ
ohama@cndbss ~ > $HOME/local/bin/sqltbl.pl SQL : select * SQL : from M_USER SQL : ; .------------------------------------------------------------------. | ID | NAME | REG_DATE | UPD_DATE | DEL_FLG | +----+-------+---------------------+---------------------+---------+ | 1 | HOGE | 2007-01-01 00:00:00 | 2007-04-01 12:00:00 | 1 | | 2 | FUGA | 2007-03-07 17:54:33 | 2007-03-07 17:54:33 | 0 | '----+-------+---------------------+---------------------+---------'
ついでに、実行結果と発行したSQL文の履歴を実行したディレクトリに
.sqlhistory というファイル名で保存します。(名前は適当)
補足:select文にしか対応してない。updateやinsert文もexcuteするとは思いますが、未検証。DDLはもっと責任持てません。describeとか対応してない。