テーブル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を使用する実際の例を見つけるのは非常に困難です。
ヒントはありますか?
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 ...
_