回答:
カラムのデータ型がpeopleあるjsonの結果であるように、json_array_elements(people)。また=、データ型には等価演算子()がありませんjson。だからあなたもGROUP BYそれに走ることはできません。もっと:
jsonbには等価演算子があるため、答えの「回避策」はjsonb、同等のものにキャストして使用することですjsonb_array_elements()。キャストはコストを追加します:
jsonb_array_elements(people::jsonb)
Postgres 9.4以降、json_array_elements_text(json)配列要素をとして返すようになりましたtext。関連:
そう:
SELECT p.name, count(*) AS c
FROM band b, json_array_elements_text(b.people) p(name)
GROUP BY p.name;
オブジェクトではtextなく名前を取得する方が便利jsonbです(テキスト表現では二重引用符で囲まれます)。 "望ましい出力"はtext、結果の最初からの必要性を示します。
GROUP BYon textデータの方がonよりも安いjsonbので、この代替の「回避策」は2つの理由でより速くなるはずです。(EXPLAIN (ANALYZE, TIMING OFF)。でテストします。)
念のため、元の回答に問題はありませんでした。コンマ(,)はと同じように「正しい」CROSS JOIN LATERAL。標準SQLで以前に定義されていても、それが劣ることはありません。見る:
どちらも、それはそれ以上の他のRDBMSに移植し、以来ではないjsonb_array_elements()かjson_array_elements_text()も無関係だと、そもそも他のRDBMSには移植できません。短いクエリはCROSS JOIN LATERALIMOでは明確になりませんが、最後のビットは私の個人的な意見です。
より明示的なテーブルと列のエイリアスp(name)とテーブル修飾された参照を使用して、p.name重複する可能性のある名前を防ぎました。nameこのような一般的な単語は、基になるテーブルの列名としてポップアップすることもありますband。その場合、暗黙的にに解決されband.nameます。単純なフォームjson_array_elements_text(people) nameは、テーブルエイリアスのみをアタッチしますvalue。関数から返された列名はまだです。ただし、リストで使用すると、name1つの列valueに解決されSELECTます。これは、期待通りの仕事に起こります。ただし、真の列名name(band.name存在する場合)が最初にバインドされます。与えられた例ではそれは噛みませんが、他の場合には装填された足の銃になる可能性があります。
最初に、一般的な「名前」を識別子として使用しないでください。多分それは単純なテストケースのためだけでした。
列peopleがプレーンなJSON配列以外のものを保持できる場合、どちらのクエリでも例外がトリガーされます。データの整合性を保証できない場合は、次の方法で防御できますjson_typeof()。
SELECT p.name, count(*) AS c
FROM band b, json_array_elements_text(b.people) p(name)
WHERE json_typeof(b.people) = 'array'
GROUP BY 1; -- optional short syntax since you seem to prefer short syntax
違反している行をクエリから除外します。
関連: