web-dev-qa-db-ja.com

Postgres 9.4でJSON配列要素でjson_to_recordを使用すると「エラー:不正な形式の配列リテラル」

これは問題をうまく説明しています:

列bがテキストではなく配列である場合、以下が機能します。

select * 
from json_to_record('{"a":1,"b":["hello", "There"],"c":"bar"}') 
    as x(a int, b text, d text);

 a |         b          | d
---+--------------------+---
 1 | ["hello", "There"] |

しかし、b列を配列として定義すると、次のエラーが発生します。

select * 
from json_to_record('{"a":1,"b":["hello", "There"],"c":"bar"}') 
    as x(a int, b text[], d text)

ERROR:  malformed array literal: "["hello", "There"]"
DETAIL:  "[" must introduce explicitly-specified array dimensions.

どうすれば説得/強制できますjson_to_record(またはjson_populate_record)JSON配列をターゲット列タイプのPostgres配列に変換するには?

9
Taytay

クリスの答えのほんの少しのバリエーション:

SELECT a, translate(b, '[]', '{}')::text[] AS b, d
FROM json_to_record('{"a": 1, "b": ["hello", "There"], "c": "bar"}')
AS x(a int, b text, d text);

考え方は同じです。JSON配列を配列にマッサージします。この場合は、配列リテラルを使用します。少しすっきりしたコードに加えて(私はそれが好きですが、正規表現は通常、この点ではあまり役に立ちません)、それも少し速く見えます:

CREATE TABLE jsonb_test (
    id serial,
    data jsonb
);

INSERT INTO jsonb_test (id, data)
SELECT i, format('{"a": %s, "b": ["foo", "bar"], "c": "baz"}', i::text)::jsonb 
FROM generate_series(1,10000) t(i);

SELECT a, string_to_array(regexp_replace(b, '\[*\"*\s*\]*','','g'),',') AS b, d
FROM jsonb_test AS j, 
LATERAL json_to_record(j.data::json) AS r(a int, b text, d text);

-- versus 

SELECT a, translate(b, '[]', '{}')::text[] AS b, d
FROM jsonb_test AS j, 
LATERAL json_to_record(j.data::json) AS r(a int, b text, d text);

このデータセットと私のテストボックスでは、正規表現バージョンは0 msの平均実行時間を示していますが、私のバージョンは210 msを示しています。

6
dezso

これは最もエレガントなソリューションではないかもしれませんが、問題を解決します...

_SELECT a,string_to_array(regexp_replace(b, '\[*\"*\s*\]*','','g'),',') AS b,d
FROM json_to_record('{"a":1,"b":["hello", "There"],"c":"bar"}')
AS x(a int, b text, d text);
_

それがどのように機能するかは非常に簡単です:

Firsttextb文字列を取得し、有用な情報まで削除します。これはregexp_replace()を使用して行われます

_regexp_replace(b, '\[*\"*\s*\]*','','g')
_

_[_、_"_、_]_、および空白文字のすべてのインスタンスを削除する、またはより具体的には、これらの文字のインスタンスを_''_に置き換えて適用するこれはグローバルにフラグ_'g'_を使用して通知されます。

Nextstring_to_array()を使用して文字列を配列に分割するだけ

_string_to_array(your_string,',')
_

この場合、_your_string_は上記のregexp_replace()の結果です。 2番目の引数_','_は、項目がカンマ区切りであることをstring_to_array()に示しました。

これにより、目的のエントリを含む_text[]_フィールドが生成されます。

1
Chris