昨日psqlのメタコマンドを使って一応できたものの、出力形式の指定とBOM付きにするコマンドが別々で、その間にクエリが入る今いちな格好。で今日はCOPYコマンドでやってみました。でも結論的には昨日の方がまだまし。今日のは実用性が低いので「補足」にします。実行環境はサーバがWindows9.5.3、クライアントがCygwinpsql。

ところでPostgreSQLCOPYコマンドには2種類あり、一つはSQLとしてサーバが実行するもの。もう一つはpsqlのメタコマンドとしてクライアントが実行するもの。構文やオプションは共通ですが、今日の内容に関連して下記の違いがあります。

• (1)SQL版 : TO PROMGRAM構文で指定する外部コマンドが、「サーバの環境」今日の場合はWindowsで実行される。
• (2)psql版 : TO PROMGRAM構文で指定する外部コマンドが、「クライアントの環境」今日の場合はCygwinで実行される。
• (3)SQL版は普通のSQLなので改行を自由に挿入できるが、psql版はメタコマンドなので全体を1行で入力する必要がある。
• ※TO PROGRAM構文はPostgreSQL 9.3以降で使用可

(1)により、SQL版でUnixライクなシェルコマンドを使うのは手間がかかるので今日は使わず。不可能ではないけど(コマンドを用意して、サーバ起動時にパスを通す)。もう一方のpsqlでやってみると ↓ こうなります。
# \copy ( YOUR QUERY in 1 row ) to program '(echo -ne "\xEF\xBB\xBF"; cat) > OUTPUT.csv' (format csv, header true, null '')


さらに改行をCRLFに置換すると ↓ こう。sedコマンドのクォートが二重引用符だと何故か動かなかったので(実行はできるがスルーされる)、シングルクォートが入れ子になってます。
# \copy ( YOUR QUERY in 1 row ) to program '(echo -ne "\xEF\xBB\xBF"; cat) | sed '':loop; N; $!b loop; ;s/\n/\r\n/g'' > OUTPUT.csv' (format csv, header true, null '')


↓ 比較のため
昨日のバージョンを再掲。メタコマンドの間にSQLが入る格好ですが、その部分は改行自由。今日のより使いやすいと思います。
# \encoding utf8
# \f ',' \\ \t off \\ \pset footer off \\ \pset format unaligned \\ \x off
# YOUR QUERY
...
...
\g | (echo -ne "\xEF\xBB\xBF"; cat) | sed ':loop; N; $!b loop; ;s/\n/\r\n/g' > OUTPUT.csv



以下、実行例です。↓ は改行処理なし(BOM付きUTF-8のみ)で、昨日と同じ外部テーブルを出力したもの。通常のテーブル
やビューは「\copyテーブル名」と書けますが、こちらはSQLにしないと駄目で、コマンドがさらに長くなってしまう…。(翌日訂正 : ビューもSQLにする必要がありました。)
\copy (select * from csv_utf8._001) to program '(echo -ne "\xEF\xBB\xBF"; cat) > /test0710_1.csv' (format csv, header true, null '')


↓ 昨日と同様、出力されたCSVを直接Excel2013にドラッグ&ドロップ。文字化けなしで正常に開けます。


↓ さらに改行をCRLFに置換。主にメモ帳対策です(LFだけでは無効。Windows7より後のOSでは知らないけど)。出力ファイルを開くと確かに改行されてます。
\copy (select * from csv_utf8._001) to program '(echo -ne "\xEF\xBB\xBF"; cat) | sed '':loop; N; $!b loop; ;s/\n/\r\n/g'' > /test0710_2.csv' (format csv, header true, null '')


今日のが使いづらいのは、1行で書かなきゃいけないのに加え、出力ファイル名が途中に来ること。TO PROGRAMで渡す外部コマンドの最後にそれがあり、その後に(format csv, ...)の出力形式オプションを持ってくる必要があるからです。

BOM付きを強制するExcelとか、LF改行を無視するメモ帳が滅びるのを願いつつ、当面は
昨日の方法でやり過ごそうと思います。