web-dev-qa-db-ja.com

postgresqlで空のJSONオブジェクトを作成する方法は?

データ・モデル

人は、名前と複数の属性を持つメタテーブル行としてデータベースに表されます。これらの属性は、キーと値のペアとしてデータテーブルに格納されます(キーと値は別々の列にあります)。 Datamodel簡略化されたデータモデル

これで、すべてのユーザー(name)とそのすべての属性(data)を取得するクエリがあります。属性は、JSONオブジェクトとして別の列に返されます。次に例を示します。

name      data
Florian   { "age":25 }
Markus    { "age":25, "color":"blue" }
Thomas    {}

SQLコマンドは次のようになります。

SELECT
  name,
  json_object_agg(d.key, d.value) AS data,
FROM meta AS m
JOIN (
  JOIN d.fk_id, d.key, d.value AS value FROM data AS d
  ) AS d
ON d.fk_id = m.id
GROUP BY m.name;

問題

今私が直面している問題は、Key-valueテーブルに属性が格納されていないThomasのようなユーザーが、select関数で表示されないことです。これは、JOINのみを実行し、LEFT OUTER JOINは実行しないためです。

LEFT OUTER JOINを使用すると問題が発生し、json_object_aggNULLの値を集計しようとしてエラーで終了します。

アプローチ

1.キーと値の空のリストを返す

したがって、ユーザーのkey-columnNULLであるかどうかを確認し、空の配列を返して、json_object_aggが空の[〜# 〜] json [〜#〜]オブジェクト。

しかし、SQLで空の配列を作成する関数は実際にはありません。私が見つけた最も近いものはこれでした:

select '{}'::text[];

COALESCEと組み合わせると、クエリは次のようになります。

json_object_agg(COALESCE(d.key, '{}'::text[]), COALESCE(d.value, '{}'::text[])) AS data

しかし、これを使用しようとすると、次のエラーが発生します。

ERROR:  COALESCE types text and text[] cannot be matched
LINE 10:     json_object_agg(COALESCE(d.key, '{}'::text[]), COALES...
                                                ^
Query failed
PostgreSQL said: COALESCE types text and text[] cannot be matched

したがって、実行時のd.keyは単一の値であり、配列ではないようです。

2. JSON作成を分割して空のリストを返す

だから私はjson_object_aggを取り、それをjson_objectで置き換えようとしましたaggregate私にとってキーではありません:

json_object(COALESCE(array_agg(d.key), '{}'::text[]), COALESCE(array_agg(d.value), '{}'::text[])) AS data

しかし、そこにnull value not allowed for object keyというエラーが表示されます。したがって、COALESCEは配列が空であることを確認しません。

見積もり

それで、結合された列が空であるかどうかをチェックする関数があり、もしそうであれば単純なJSONオブジェクトだけを返しますか?

または、私の問題を解決する他の解決策はありますか?

14
cansik

_left join_をcoalesce()とともに使用します。デフォルト値として_'{}'::json_を使用します。

_select name, coalesce(d.data, '{}'::json) as data
from meta m
left join (
    select fk_id, json_object_agg(d.key, d.value) as data
    from data d
    group by 1
    ) d
on m.id = d.fk_id;

  name   |                data                
---------+------------------------------------
 Florian | { "age" : "25" }
 Marcus  | { "age" : "25", "color" : "blue" }
 Thomas  | {}
(3 rows)    
_
21
klin