回答:
カラムのデータ型が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 BY
on text
データの方がonよりも安いjsonb
ので、この代替の「回避策」は2つの理由でより速くなるはずです。(EXPLAIN (ANALYZE, TIMING OFF)
。でテストします。)
念のため、元の回答に問題はありませんでした。コンマ(,
)はと同じように「正しい」CROSS JOIN LATERAL
。標準SQLで以前に定義されていても、それが劣ることはありません。見る:
どちらも、それはそれ以上の他のRDBMSに移植し、以来ではないjsonb_array_elements()
かjson_array_elements_text()
も無関係だと、そもそも他のRDBMSには移植できません。短いクエリはCROSS JOIN LATERAL
IMOでは明確になりませんが、最後のビットは私の個人的な意見です。
より明示的なテーブルと列のエイリアスp(name)
とテーブル修飾された参照を使用して、p.name
重複する可能性のある名前を防ぎました。name
このような一般的な単語は、基になるテーブルの列名としてポップアップすることもありますband
。その場合、暗黙的にに解決されband.name
ます。単純なフォームjson_array_elements_text(people) name
は、テーブルエイリアスのみをアタッチしますvalue
。関数から返された列名はまだです。ただし、リストで使用すると、name
1つの列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
違反している行をクエリから除外します。
関連: