明示的なJSONスキーマまたは規則がないJSON列を処理しようとしています。 JSON内にはさまざまなキーがあります。一部のキーは存在しません。一部のキーは存在しますが、空の文字列値です。
例えば:
CREATE TABLE json_table (
id int,
json_data json
);
INSERT INTO json_table (id, json_data) VALUES
(1, '{"foo" : "bar", "baz": "biz"}');
(2, '{"foo" : "", "baz": "biz"}');
(3, '{"hello" : "world"}');
(4, '{"hello" : "world2", "foo" : "bar2", "baz" : "" }');
このテーブルをクエリして、空ではない文字列であるキーと値のペアのみでjson_data
のサブセットを選択/生成することはできますか?
このテーブルをクエリして、指定されたリスト内にあるJSONキーを含むレコードを選択することはできますか? (私は基本的に、キー「foo」を持つjson_data
のレコードを検索したい)
#2の場合、json_data
キーが正規表現パターン内にあるレコードのみを選択するソリューションがあります。
SELECT tmp.*
FROM (
SELECT id,
ARRAY(SELECT json_object_keys(json_data))::text AS keys
FROM json_table
) tmp
WHERE tmp.keys LIKE ANY(ARRAY['%foo%', '%bar%']);
これにより、
"id","keys"
1,"{foo,baz}"
2,"{foo,baz}"
4,"{hello,foo,baz}"
ただし、注意が必要です。キーはあるが空の文字列値を持つレコードを返します!これに#1のソリューションを組み込み、JSONを「有効な」キーと値のペアのみに事前にフィルタリングする方法はありますか?
集計中に空の値を削除できます。そして、最後の選択で配列演算子を使用して、特定のキーを含む行のみを取得します。
SELECT tmp.*
FROM (
SELECT id,
ARRAY(SELECT t.k
from json_each_text(json_data) as t(k,v)
where nullif(trim(t.v),'') is not null) AS keys
FROM json_table
) tmp
WHERE keys && array['foo','bar']
;
キーだけでなく完全なJSON値が必要な場合は、次のようなものを使用できます。
SELECT tmp.*
FROM (
SELECT id,
(SELECT jsonb_object_agg(t.k, t.v)
from json_each_text(json_data) as t(k,v)
where nullif(trim(t.v),'') is not null) AS keys
FROM json_table
) tmp
WHERE keys ?| array['foo','bar']
;
(この場合、処理がはるかに柔軟であるため、この場合の結果にはjsonb
を使用しています。一般に、最近ではjsonよりもjsonbを使用することをお勧めします)
Jsonを頻繁にクリーンアップする必要がある場合は、そのための関数を作成することを検討してください。
create function non_empty_values(p_input jsonb)
returns jsonb
as
$$
SELECT jsonb_object_agg(t.k, t.v)
from jsonb_each(jsonb_strip_nulls(p_input)) as t(k,v)
where trim(t.v::text) <> '';
$$
language sql
immutable;