web-dev-qa-db-ja.com

PostgreSQLでのJSONBのクエリ

テーブルpersonsがあり、これにはidとJSONBベースのdata列の2つの列が含まれています(このテーブルは、デモ用に試してみたものですPostgreSQLのJSONサポート)。

ここで、2つのレコードが含まれているとします。

1, { name: 'John', age: 30 }
2, { name: 'Jane', age: 20 }

今、私は25歳以上のすべての人の名前を取得したいと思います。私が試したのは:

select data->'name' as name from persons where data->'age' > 25

残念ながら、これはエラーになります。 ->>の代わりに->を使用して解決できますが、数値は比較されないため、文字列としての表現なので、比較は期待どおりに機能しなくなります。

select data->'name' as name from persons where data->>'age' > '25'

次に、->intへのキャストを使用して実際に問題を解決できることを理解しました。

select data->'name' as name from persons where cast(data->'age' as int) > 25

これは機能しますが、実際のタイプ(JSONドキュメントのageのタイプはとにかくnumberです)を知っている必要があるのはいいことではないので、なぜPostgreSQLだけでそれを理解できないのですか? ?)。

次に、::構文を使用してtextに手動で変換すると、すべてが期待どおりに機能することもわかりました。

select data->'name' as name from persons where data->'age'::text > '25'

年齢ではなく名前でこれを試しても、うまくいきません:

select data->'name' as name from persons where data->'name'::text > 'Jenny'

これはエラーになります:

タイプjsonの無効な入力構文

明らかに、私はここで何かを得ません。残念ながら、PostgreSQLでJSONを使用する実際の例を見つけるのは非常に困難です。

ヒントはありますか?

13
Golo Roden

jsonb値をintegerにキャストしようとしているため、これは機能しません。

select data->'name' as name from persons where cast(data->'age' as int) > 25

これは実際に機能します:

SELECT data->'name' AS name FROM persons WHERE cast(data->>'age' AS int) > 25;

またはより短い:

_SELECT data->'name' AS name FROM persons WHERE (data->>'age')::int > 25;
_

この:

_SELECT data->'name' AS name FROM persons WHERE data->>'name' > 'Jenny';
_

2つの 演算子_->_および_->>_ および operator precedence と混同しているようです。キャスト_::_は、json(b)演算子よりも強力にバインドします。

タイプを動的に把握する

これはあなたの質問のより興味深い部分です:

とにかく、JSONドキュメントの年齢のタイプは数値なので、なぜPostgreSQLだけでそれを理解できないのでしょうか。

SQLは厳密に型指定された言語であり、同じ式を1つの行でintegerと評価し、次の行でtextと評価することはできません。ただし、テストのboolean結果のみに関心があるため、 jsonb_typeof()の結果に応じて分岐するCASE式でこの制限を回避できます。

_SELECT data->'name'
FROM   persons
WHERE  CASE jsonb_typeof(data->'age')
        WHEN 'number'  THEN (data->>'age')::numeric > '25' -- treated as numeric
        WHEN 'string'  THEN data->>'age' > 'age_level_3'   -- treated as text
        WHEN 'boolean' THEN (data->>'age')::bool           -- use boolean directly (example)
        ELSE FALSE                                         -- remaining: array, object, null
       END;
_

_>_演算子の右側にある型指定されていない文字列リテラルは、左側の値のそれぞれの型に自動的に強制変換されます。型付きの値をそこに置く場合、システムに登録されている適切な暗黙的キャストがない限り、型は一致するか、明示的にキャストする必要があります。

すべての数値値が実際にintegerであることを知っている場合、次のこともできます。

_... (data->>'age')::int > 25 ...
_
14