次のようなドキュメントdata
を保持する列がありますjson
。
{
"name": "foo",
"tags": ["foo", "bar"]
}
ネストされたtags
配列を連結文字列(foo, bar
)に変換したいと思います。それはarray_to_string()
理論上の関数で簡単に可能になります。ただし、この関数はjson
配列には作用しません。だから私はこのjson
配列をPostgres に変える方法を疑問に思いますarray
か?
次のようなドキュメントdata
を保持する列がありますjson
。
{
"name": "foo",
"tags": ["foo", "bar"]
}
ネストされたtags
配列を連結文字列(foo, bar
)に変換したいと思います。それはarray_to_string()
理論上の関数で簡単に可能になります。ただし、この関数はjson
配列には作用しません。だから私はこのjson
配列をPostgres に変える方法を疑問に思いますarray
か?
回答:
明らかにこの投稿に触発されて、Postgres 9.4は足りない機能を追加し
ました。パッチのLaurence RoweとコミットしてくれたAndrew Dunstanに感謝します!
JSON配列のネストを解除します。次に、array_agg()
またはARRAYコンストラクターを使用して、Postgres 配列を構築します。またはstring_agg()
、text
文字列を作成します。
LATERAL
または相関サブクエリの行ごとにネストされていない要素を集約します。その後、元の順序は保持され、外部クエリにORDER BY
、GROUP BY
または一意のキーさえ必要ありません。見る:
jsonb
次のすべてのSQLコードで、「json」を「jsonb」に置き換えます。
SELECT t.tbl_id, d.list
FROM tbl t
CROSS JOIN LATERAL (
SELECT string_agg(d.elem::text, ', ') AS list
FROM json_array_elements_text(t.data->'tags') AS d(elem)
) d;
短い構文:
SELECT t.tbl_id, d.list
FROM tbl t, LATERAL (
SELECT string_agg(value::text, ', ') AS list
FROM json_array_elements_text(t.data->'tags') -- col name default: "value"
) d;
関連する:
相関サブクエリのARRAYコンストラクター:
SELECT tbl_id, ARRAY(SELECT json_array_elements_text(t.data->'tags')) AS txt_arr
FROM tbl t;
関連する:
微妙な違い:null
要素は実際の配列に保存されます。これはtext
、null
値を含むことができない文字列を生成する上記のクエリでは不可能です。真の表現は配列です。
繰り返し使用する場合は、これをさらに簡単にするために、ロジックを関数にカプセル化します。
CREATE OR REPLACE FUNCTION json_arr2text_arr(_js json)
RETURNS text[] LANGUAGE sql IMMUTABLE AS
'SELECT ARRAY(SELECT json_array_elements_text(_js))';
それをSQL関数にして、より大きなクエリでインライン化できるようにします。
それを作るIMMUTABLE
大きなクエリで繰り返し評価を避け、インデックス式でそれを可能にするために(それがあるため)。
コール:
SELECT tbl_id, json_arr2text_arr(data->'tags')
FROM tbl;
db <> fiddle here
関数を使用しますjson_array_elements()
。しかし、二重引用符で囲まれた文字列を取得します。
外部クエリに集約された代替クエリ。CROSS JOIN
配列が欠落しているか空の行を削除します。要素の処理にも役立つ場合があります。集約するには一意のキーが必要です。
SELECT t.tbl_id, string_agg(d.elem::text, ', ') AS list
FROM tbl t
CROSS JOIN LATERAL json_array_elements(t.data->'tags') AS d(elem)
GROUP BY t.tbl_id;
引用符付きの文字列を使用したARRAYコンストラクター:
SELECT tbl_id, ARRAY(SELECT json_array_elements(t.data->'tags')) AS quoted_txt_arr
FROM tbl t;
null
上記とは異なり、テキスト値「null」に変換されることに注意してください。正しくない、厳密に言えば、あいまいな可能性があります。
かわいそうな人の引用なしtrim()
:
SELECT t.tbl_id, string_agg(trim(d.elem::text, '"'), ', ') AS list
FROM tbl t, json_array_elements(t.data->'tags') d(elem)
GROUP BY 1;
tblから単一の行を取得します。
SELECT string_agg(trim(d.elem::text, '"'), ', ') AS list
FROM tbl t, json_array_elements(t.data->'tags') d(elem)
WHERE t.tbl_id = 1;
相関サブクエリを形成する文字列:
SELECT tbl_id, (SELECT string_agg(trim(value::text, '"'), ', ')
FROM json_array_elements(t.data->'tags')) AS list
FROM tbl t;
ARRAYコンストラクター:
SELECT tbl_id, ARRAY(SELECT trim(value::text, '"')
FROM json_array_elements(t.data->'tags')) AS txt_arr
FROM tbl t;
元の(時代遅れの)SQL Fiddle。
db <> fiddle here。
関連する:
JSON配列から適切な値を返すにはjson_array_elements_text(json)
、が必要です。しかし、それはJSON関数の提供された兵器庫から欠落しているようです。または、スカラー値から値を抽出する他の関数。私もそれを見逃しているようです。
だから、私はで即興演奏しましたが、それは自明でないケースでは失敗します...json_array_elements(json)
text
text
JSON
trim()
to_jsonb()
配列-> jsonb変換に使用します。
SELECT ARRAY(SELECT json_array_elements_text(_js))
本当に配列の順序が保存されていることを保証しますか?オプティマイザーは、json_array_elements_textから出力される行の順序を理論的に変更することを許可されていませんか?
PG 9.4以降
受け入れられた答えは間違いなくあなたが必要とするものですが、ここでは簡単にするために私がこれに使用するヘルパーです:
CREATE OR REPLACE FUNCTION jsonb_array_to_text_array(
p_input jsonb
) RETURNS TEXT[] AS $BODY$
DECLARE v_output text[];
BEGIN
SELECT array_agg(ary)::text[]
INTO v_output
FROM jsonb_array_elements_text(p_input) AS ary;
RETURN v_output;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
それからちょうど:
SELECT jsonb_array_to_text_array('["a", "b", "c"]'::jsonb);
この質問はPostgreSQLメーリングリストで尋ねられ、JSONフィールド抽出演算子を介してJSONテキストをPostgreSQLテキストタイプに変換するこのハック的な方法を思いつきました。
CREATE FUNCTION json_text(json) RETURNS text IMMUTABLE LANGUAGE sql
AS $$ SELECT ('['||$1||']')::json->>0 $$;
db=# select json_text(json_array_elements('["hello",1.3,"\u2603"]'));
json_text
-----------
hello
1.3
☃
基本的に、値を単一要素の配列に変換し、最初の要素を要求します。
別のアプローチは、この演算子を使用してすべてのフィールドを1つずつ抽出することです。しかし、大きな配列の場合、各配列要素のJSON文字列全体を解析する必要があるため、これはおそらく遅くなり、O(n ^ 2)の複雑さが生じます。
CREATE FUNCTION json_array_elements_text(json) RETURNS SETOF text IMMUTABLE LANGUAGE sql
AS $$ SELECT $1->>i FROM generate_series(0, json_array_length($1)-1) AS i $$;
db=# select json_array_elements_text('["hello",1.3,"\u2603"]');
json_array_elements_text
--------------------------
hello
1.3
☃
いくつかのオプションをテストしました。これが私のお気に入りのクエリです。idフィールドとjsonフィールドを含むテーブルがあるとします。jsonフィールドには、pg配列に変換したい配列が含まれています。
SELECT *
FROM test
WHERE TRANSLATE(jsonb::jsonb::text, '[]','{}')::INT[]
&& ARRAY[1,2,3];
それはどこでも動作し、他よりも高速ですが、松葉杖に見えます)
最初にjson配列がテキストとしてキャストされ、次に角かっこをかっこに変更します。最後に、テキストは必要なタイプの配列としてキャストされています。
SELECT TRANSLATE('[1]'::jsonb::text, '[]','{}')::INT[];
また、text []配列を好む場合
SELECT TRANSLATE('[1]'::jsonb::text, '[]','{}')::TEXT[];
SELECT TRANSLATE('{"name": "foo", "tags": ["foo", "bar"]}'::jsonb::text, '[]','{}')::INT[]; ERROR: malformed array literal: "{"name": "foo", "tags": {"foo", "bar"}}"
これがどのように機能するかについての説明を追加する必要があると思います。
SELECT translate('["foo", "bar"]'::jsonb::text, '[]','{}')::INT[]; ERROR: invalid input syntax for integer: "foo"
それは...そう爆弾プルーフではありません
この質問への回答から取られたこれらのいくつかの機能は、私が使用しているものであり、彼らは素晴らしい仕事をしています
CREATE OR REPLACE FUNCTION json_array_casttext(json) RETURNS text[] AS $f$
SELECT array_agg(x) || ARRAY[]::text[] FROM json_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;
CREATE OR REPLACE FUNCTION jsonb_array_casttext(jsonb) RETURNS text[] AS $f$
SELECT array_agg(x) || ARRAY[]::text[] FROM jsonb_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;
CREATE OR REPLACE FUNCTION json_array_castint(json) RETURNS int[] AS $f$
SELECT array_agg(x)::int[] || ARRAY[]::int[] FROM json_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;
CREATE OR REPLACE FUNCTION jsonb_array_castint(jsonb) RETURNS int[] AS $f$
SELECT array_agg(x)::int[] || ARRAY[]::int[] FROM jsonb_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;
それらのそれぞれで、空の配列と連結することによって、彼らは私の脳を少し悩ませたケースを処理します。それでjson
/ から空の配列をキャストしようとjsonb
すると、空の配列({}
)は期待どおりです。それらにはある程度の最適化があると確信していますが、概念の説明を簡単にするために、それらはそのまま残されています。
json_extract_path_text(your_column, 'tags')
あなたが探しているもの?