web-dev-qa-db-ja.com

csvファイルのpostgres jsonデータにインポートする

テーブルのデータを含むcsvファイルをpostgresにインポートしようとしています。テーブルの列の1つにjsonbタイプがあります。

csvファイルの1行に次のようなものが含まれています

1,{"a":"b"}

テーブルにスキーマがあるとします

id              | smallint          | 
data            | jsonb             | 

データを挿入しようとすると、すべて正常に動作します

INSERT INTO table VALUES (1, '{"a":"b"}');

でファイルから直接インポートしようとしています

COPY table FROM '/path/to/file.csv' DELIMITER ',' csv;

次のエラーが表示されます。

ERROR:  invalid input syntax for type json
DETAIL:  Token "a" is invalid.
CONTEXT:  JSON data, line 1: {a...
COPY availability, line 1, column services: "{a: b}"

フィールドを'"\"および\'で引用しようとしましたが、何も機能しません。

それを行う正しい構文はどれですか?

7
marcosh

PostgreSQLのCOPYコマンドはめったに理想的ではありませんが、しばしば機能します。参考までに、これを推測するよりも良い方法があります。

CREATE TEMP TABLE baz AS
  SELECT 1::int, '{"a":"b"}'::jsonb;

これは正確なサンプルデータです。これで、さまざまな設定をテストできます。

# COPY baz TO STDOUT;
1   {"a": "b"}

COPY baz TO STDOUT DELIMITER ',';
1,{"a": "b"}

上記はあなたが質問した正確なデータを生成することがわかります...

COPY baz TO '/tmp/data.csv' DELIMITER ',';

問題はない。少なくともPostgreSQL 9.5ではできません。

CSVモード

だからあなたの問題はどこですか、それはCSVモードでです。観察する、

# COPY baz TO STDOUT;
1   {"a": "b"}
# COPY baz TO STDOUT CSV;
1,"{""a"": ""b""}"

これらの2つが異なることがわかります。上記のCSVモードで生成された形式を想定したCSVモードで非CSVファイルをロードしてみましょう。

TRUNCATE baz;
COPY baz FROM '/tmp/data.csv' DELIMITER ',' CSV;
ERROR:  invalid input syntax for type json
DETAIL:  Token "a" is invalid.
CONTEXT:  JSON data, line 1: {a...
COPY baz, line 1, column jsonb: "{a: b}"

エラーになります。その理由は RFC 418 に由来します

各フィールドは二重引用符で囲まれている場合と囲まれていない場合があります(ただし、Microsoft Excelなどの一部のプログラムでは二重引用符がまったく使用されていません)。 フィールドが二重引用符で囲まれていない場合、フィールド内に二重引用符が表示されないことがあります。

  1. したがって、 JSON RFC 4627 は、名前/値のペアのオブジェクトのnamesを指定するために、二重引用符が必要な文字列である必要があります。
  2. そして CSV RFC 418 は、フィールド内に二重引用符がある場合、フィールド全体を引用する必要があることを指定します。

この時点で2つのオプションがあります。

  1. CSVモードは使用しないでください。
  2. または、内側の引用符をエスケープします。

したがって、これらはCSVモードの同じオプションで有効な入力になります。

#COPY baz TO STDOUT DELIMITER ',' CSV ESCAPE E'\\';
1,"{\"a\": \"b\"}"

# COPY baz TO STDOUT DELIMITER ',' CSV;
1,"{""a"": ""b""}"
5
Evan Carroll

解決策を見つけた、postgresは"エスケープ文字として、正しい形式にする必要があります

{"""a""": """b"""}
3
marcosh

他の回答で述べたように、 CSV そしてその JSON 仕様(そしておそらく postgresql 仕様)は多少互換性がありません。少なくとも単純な形で彼らに戦いを止めさせるには、それらが判読不能な混乱になるまで物事を脱出する必要があります。使用していない CSV モードはさらに悪い コピー 何でも死ぬ JSON 埋め込まれた新しい行、バックスラッシュ、または引用符に問題があります。

もっと複雑な入力でのみ、まったく同じ問題が発生しました。 ENUM 型、整数、複素数 JSON 田畑。ウィットするには:

create table messages( a blab, b integer, c text, d json, e json);

典型的な場所 JSONsは{"default":"little","sms":"bigger"}および["name","number"]。それらの山をインポートしてみてください コピー コマンド:コン​​マが JSON 引用符を取得しないでください!私はこれを見つけるまで何時間も費やします この素晴らしいブログ投稿 これは問題の原因とそれから抜け出すために必要なオプションを指摘しました。

基本的には、区切り文字と引用符のフィールドを、あなたの中にないことを保証できるものに変更する必要があります JSON データ。私の場合、私はたくさんを保証できるので、私はただ行くことができます

COPY messages( a, b, c, d, e) from stdin  csv quote '^' delimiter '|';
malfunction|5|La la la|{"default":"little","sms":"bigger"}|["name","number"]

見やすく、読みやすく、お気に入りのテキストマングラーのマイナーな文字置換で簡単にアクセスでき、何も逃げません。上記で使用されている文字があなたの中にないことを保証できない場合 JSON 次に、かなり風変わりなe'\x01'およびe'\x02'として JSON 仕様はそれらを完全に違法と見なします。読みやすさなどは劣りますが、正確には正確です。

一部のように、埋め込まれた改行に注意してください JSON ジェネレーターは読みやすさの目的で出力する傾向がありますが、それでも「いいえ」ではないので、あなたはそれらをあなたのフィルターから取り除く必要があります JSON

1
Nadreck