csvってどうやって出力してますか?

このエントリは JPOUG Advent Calendar 参加ブログで一日目です。


Advent Calendarについては、このあたりを見ていただくとして、早速本題に入ります。


地味な話題ですが、みなさん、Oracle Databaseからcsvってどうやって出力していますか?
私は仕事柄結構csv出力する機会があり、こんな風にSQLPLUSから出力してました。


csv.sql

set lin 999 --1行の長さを999文字にする
set colsep ,--区切り文字を「,」にする
set feedback off -- xx行が表示されました のようなメッセージ(フィードバック)表示をOFFにする
set pages 0 --ページをOFF(ヘッダ、フッタ等を非表示にする)
set echo off -- スクリプト実行時にエコー表示しない

spool test2.csv
select 'EMPNO','ENAME','JOB','MGR','HIREDATE','SAL','COMM','DEPTNO' from dual;--列名表示
--colsepだけだと列が固定長で表示されてしまうため、||で各列を連結している表示
select EMPNO||','||ENAME||','||JOB||','||MGR||','||HIREDATE||','||SAL||','||COMM||','||DEPTNO from EMP;
spool off;

実行例

SQL>@csv.sql

出力例(test2.csv)

EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO
7369,SMITH,CLERK,7902,80-12-17,800,,20
7499,ALLEN,SALESMAN,7698,81-02-20,1600,300,30
7521,WARD,SALESMAN,7698,81-02-22,1250,500,30
7566,JONES,MANAGER,7839,81-04-02,2975,,20
7654,MARTIN,SALESMAN,7698,81-09-28,1250,1400,30
7698,BLAKE,MANAGER,7839,81-05-01,2850,,30
7782,CLARK,MANAGER,7839,81-06-09,2450,,10
7788,SCOTT,ANALYST,7566,87-04-19,3000,,20
7839,KING,PRESIDENT,,81-11-17,5000,,10
7844,TURNER,SALESMAN,7698,81-09-08,1500,0,30
7876,ADAMS,CLERK,7788,87-05-23,1100,,20
7900,JAMES,CLERK,7698,81-12-03,950,,30
7902,FORD,ANALYST,7566,81-12-03,3000,,20
7934,MILLER,CLERK,7782,82-01-23,1300,,10


出力自体はこれでほとんど問題ないのですが、実行するSQLは毎回違うので、
その度に、csv.sqlみたいなものを毎回書き直すの面倒で仕方ないです。

そこで、csv出力のいい方法がないか調べてみました。


1. Oracle SQL Developer
Oracle 11g以降はOracle Clientインストール時に「ランタイム」もしくは、
「管理者」を選ぶともれなく、Oracle SQL Developerもインストールされます。
このSQL Developerがなかなか便利でPL/SQLの開発だけでなく、SQL文の実行も出来たりするのですが、
SQLの実行結果を様々なフォーマットでエクスポートする機能があり、
csv形式でエクスポートする事ができます。エクスポートされたcsvは各列が「"」で括ってあるため、
改行を含んだものでも綺麗な形でEXCEL等で取り込むことが出来ます。

なお、Oracle SQL Developerは初回起動時にJavaのパス入力を求められますが、Oracle Clientインストール時に
合わせてJDKもインストールされるため、Javaがインストールされていない環境でも「ORACLE_HOME\jdk\bin\java.exe」を指定すれば
Oracle SQL Developer を使うことが出来ます。



2. ちょっとperlスクリプト書いちゃう
Oracle Client(Windows版)インストール時に「ランタイム」もしくは、「管理者」を選ぶともれなく、perlもインストールされます。
このPerlですが、Oracle Databaseへ接続するためのライブラリ DBD::Oracleも含まれているため、
Oracle Clientをインストールしておけば、ちょっとしたOracle Database操作のスクリプトを書くことが出来ます。


DBD::Oracleの習作も含めて、任意のSQL文をcsv出力するperlスクリプトを書いてみます。
(にわかperlerなので、DBIの使い方はもろもろ、stackoverflow.comperlmonks.orgをベースにスクリプト書いてます。


db2csv.pl

#以下をほぼほぼ使用して、引数にOracle接続子、標準入力にSQL文を入れるようにしている
#http://stackoverflow.com/questions/65447/getting-data-from-an-oracle-database-as-a-csv-file-or-any-other-custom-text-for
#http://www.perlmonks.org/?node_id=264623


use DBI;
use DBD::Oracle;

#引数を/,@で区切ってそれぞれ、ユーザ名、パスワード、TNS名として取得
@args=split(/\/|@/,$ARGV[0]);
$user = $args[0];
$pass = $args[1];
$db = $args[2];

$dbh = DBI->connect( "dbi:Oracle:$db", $user, $pass );

print "SQL>";

$sql="";
while (<STDIN>){
  $sql=$sql.$_;
  last if($sql=~/;/);
}
#入力で「;」があったらSQLの終了と判定。本当は/でも判定したいけど、除算の/と区別つかないので断念
$sql =~ s/;//;

$dbh->{LongReadLen} = 65535;
$dbh->{PrintError} = 0;
$sth = $dbh->prepare($sql);

$sth->execute();


if ( $dbh->err() ) { die $dbh->errstr(); }

#列名の出力
$colnames = $sth->{NAME};
print "\"";
print join "\",\"", @$colnames;
print "\"\n";

#各列データの値に「"」と「,」を付与して(csv形式にして)出力
while ( $arrayref = $sth->fetchrow_arrayref ) {
    print "\"";
    print join "\",\"", @$arrayref;
    print "\"\n";
}

$dbh->disconnect();


実行例(Oracle Clientに付属のperlにPATHを通して実行)

C:\Documents and Settings\Administrator>set PATH=%PATH%;C:\app\Administrator\product\11.2.0\client_1\perl\bin
C:\Documents and Settings\Administrator>perl db2csv.pl scott/tiger@ora11g
SQL>select * from emp;
"EMPNO","ENAME","JOB","MGR","HIREDATE","SAL","COMM","DEPTNO"
"7369","SMITH","CLERK","7902","80-12-17","800","","20"
"7499","ALLEN","SALESMAN","7698","81-02-20","1600","300","30"
"7521","WARD","SALESMAN","7698","81-02-22","1250","500","30"
"7566","JONES","MANAGER","7839","81-04-02","2975","","20"
"7654","MARTIN","SALESMAN","7698","81-09-28","1250","1400","30"
"7698","BLAKE","MANAGER","7839","81-05-01","2850","","30"
"7782","CLARK","MANAGER","7839","81-06-09","2450","","10"
"7788","SCOTT","ANALYST","7566","87-04-19","3000","","20"
"7839","KING","PRESIDENT","","81-11-17","5000","","10"
"7844","TURNER","SALESMAN","7698","81-09-08","1500","0","30"
"7876","ADAMS","CLERK","7788","87-05-23","1100","","20"
"7900","JAMES","CLERK","7698","81-12-03","950","","30"
"7902","FORD","ANALYST","7566","81-12-03","3000","","20"
"7934","MILLER","CLERK","7782","82-01-23","1300","","10"


まとめ
Oracle SQL Developer便利
Oracle Client入れるともれなくperlも使えるよ!


明日は
明日はRyota Watabe さんです。よろしくお願いします。