Contents


背景

PostgreSQLのデータを人にExcelで渡す時、psqlからクリップボード経由でのコピぺ(629日の記事)が手軽ですが、CSVでくれと言われる時も多いです。問題はCSVの文字コード・改行コードに色々あること。先方がそれを知っていて指定があるとか、「何でもいいよ~こっちで変換するから」と言われれば全然問題ありません。

でも中途半端に「CSV = Excelファイルのテキスト版」くらいな理解の人もいて、Excelで文字化けしたとか、メモ帳で開いたら改行されてないとか言われると面倒。↓ にあるとおり最新のExcelですら、設定によってはShift JISを自動認識しないし。同じ症状(言語設定の優先順位による問題)はExcel2007、2010、2013でも確認しました。

» Excel2016SJISで保存されているCSVファイルを開くと文字化けする


それで、互換性は下がるけど「BOM付きUTF-8」のCSVなら、ダブルクリックしてExcelで開いても文字化けしないので一応の対策にはなります(Excel2010、2013で確認。Excel2007OSが英語版のせいかダメでした)。詳細は ↓ を参照。

» Excelで開くと文字化けするUTF-8CSVを文字コードを変換せずに開く方法


似たことは、Macで作ったCP1252(ASCII以外を含む欧文)のテキストをWindowsのメモ帳で開く際の対策としても ↓ 紹介されてました。

» Stack Overflow -- iconv: Converting from Windows ANSI to UTF-8 with BOM


psqlのメタコマンドを工夫して実行

というわけで、PostgreSQLのデータを「BOM付きUTF-8CSVファイル」に出力する方法。今回はpsqlのメタコマンドを工夫して行います。

実行環境はPostgreSQL9.5.2 + Cygwinpsql。いわゆるUnixライクなシェルコマンドを使うので、Windowsコマンドプロンプトだけでは厳しいです。サンプルデータとして ↓
528日のアンカンファレンス@東京で作った日本語を含む外部テーブルを使用。
# select * from csv_utf._001 offset 10;


psqlでの実行内容です。最初にクライアントエンコーディングをUTF-8に。2行目が出力形式で「カンマ区切り、列名入り(タプルのみでない)、フッタの行数表示なし、整形なし、縦表示しない」。
詳細はドキュメントを見て下さい。その次が本題で、データ表示するSELECT文に続けてメタコマンド\gを打ち、パイプでUTF-8BOMを先頭に挿入しファイル出力しています。
# \encoding utf8
# \f ',' \\ \t off \\ \pset footer off \\ \pset format unaligned \\ \x off 

# select * from csv_utf8._001 offset 10
  \g | (echo -ne "\xEF\xBB\xBF"; cat) > test1.csv


↓ 出力されたCSVをエディタ(AkelPad)で開いたところ。ステータスバーにUTF-8とあり、BOM無しならそう表示されるので、期待どおりBOM付きで出力できてます。


このCSVWindows 7 x64英語版+ Excel2013にドラッグ&ドロップ。言語設定は ↓ こんな感じで編集言語がOSと同様に英語。Shift JISCSVは文字化けします。


↓ ドラッグ&ドロップ後。BOM付きUTF-8CSVは文字化けせず読み込めました。

別の問題として、先頭がゼロ埋めされた「本来は文字列」のコード番号が数値に変わってます。そういうExcelの仕様であり、今日の本題でないのでスルー。


さらに改行をCRLFにする

以上でExcelの件は終わり。あと冒頭で書いたように「メモ帳で開いたら改行されてない」とか言われるケースがたまにあるので、全てのLF改行をCRLF改行に置換するコマンドを追加します。この逆(CR全削除)はtrで簡単にでき情報も多いですが、こちらは手こずりました。やっと見つけたのが ↓ ここ。

» sedの使い方- 4.3改行をすべて削除


削除をCRLF改行に変え ↓ このように長いコマンドになりました。画像ではコマンドが折り返されてますが、実際は1行で入力します(メタコマンド中では改行できない)。なお今回の環境(Cygwin 2.5.1 x64)のせいかもしれませんが、sedコマンドのクォートを二重引用符にしたら動きませんでした。
# \encoding utf8
# \f ',' \\ \t off \\ \pset footer off \\ \pset format unaligned \\ \x off
-- Same as before

# select * from csv_utf8._001 offset 10
  \g | (echo -ne "\xEF\xBB\xBF"; cat) | sed ':loop; N; $!b loop; ;s/\n/\r\n/g' > test2.csv 


結果確認。Windows7 x64英語版のメモ帳で開くと ↓ 確かに改行されてます。


以上でpsqlから、Windows向けに最もオールマイティな?「BOM付きUTF-8CRLF改行」のCSVを出力できました。

ただし手順は「エンコーディング設定」→「メタコマンドで出力形式を設定」→「クエリ+メタコマンドを入力」となり、2つのメタコマンドがそれぞれ長い。これが短くなるか分からないけど、
明日は別の方法としてCOPYコマンドを検討してみます。