web-dev-qa-db-ja.com

UNIONを使用する場合、タイプjson []の等値演算子を識別できませんでした

UNIONルールを使用して、単一のテーブルで複数のクエリを実行しようとしています

2つのテーブルがあります。

  • プロジェクト(ID、名前、固定BOOLEAN)
  • スキル(プロジェクトまでのm2m)

私は最初にpinnedtrueに設定され、残りを最新のエントリで埋める行の配列を取得しようとしています(pinnedfalseに設定されています)

SELECT
  project.id AS project_id,
  project.name AS project_name,
  array_agg(json_build_object('skill_id', project_skills.id,'name', project_skills.skill)) AS skills
from project
LEFT OUTER JOIN project_skills on project.name = project_skills.project
WHERE project.pinned = true
GROUP BY project_id,project_name

UNION

SELECT
  project.id AS project_id,
  project.name AS project_name,
  array_agg(json_build_object('skill_id', project_skills.id,'name', project_skills.skill)) AS skills
from project
LEFT OUTER JOIN project_skills on project.name = project_skills.project
WHERE project.id != 1 AND project.pinned = false
GROUP BY project_id,project_name
ORDER BY project.create_date DESC LIMIT 5

このクエリを実行すると、次のエラーが表示されます

ERROR:  could not identify an equality operator for type json[]
LINE 7:   array_agg(json_build_object('skill_id', project_skills.id,...

私はこのエラーを理解していません。両方の結果からjson列を比較しようとしているので失敗していますか?

Postgres 9.4を使用しています。

25
Kannaj

UNIONを使用すると、DBMSは重複行を削除します。これを行うには、2つの行が等しい/同一であるかどうかを識別する必要があります。これは、比較している2行の各列を見て、それらが等しいかどうかを判断することを意味します。

表示されているエラーメッセージは、array_agg(json_build_object(...))を使用して列の1つが作成され、_json[]_型の値を生成します。これは「json値の配列」を意味します。 PostgresはJSON値の2つの配列を比較する方法を知らないため、UNIONが重複を生成したかどうかを判断できません。

実際に重複を削除する必要がない場合、最も簡単な解決策は_UNION ALL_を使用することで、この手順はスキップされます。

コメントで指摘されているように、do重複を削除したい場合、比較演算子が定義されている値に値をキャストできます。最も一般的な解決策はテキスト(たとえば_some_value::text_またはCAST(some_value as text))にキャストすることですが、JSONの場合は特に jsonb type が必要です。これは比較時にフォーマットを無視します。

jsonjsonbに、または_json[]_を_jsonb[]_にキャストできます。または、この例では、array_agg(jsonb_build_object(...))ではなくarray_agg(json_build_object(...))で直接jsonbをビルドできます。

47
IMSoP

私がしなければならなかったことは、UNION ALL-これは、クエリ間でjson型を比較しようとすることを無視すると思います。

3
Kannaj