PostgreSQLでのJSONBのクエリ


14

私は、テーブルを持つpersons2つの列が含まれている、idとJSONBベースのdata列を(この表は単なる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

これは機能しますが、実際のタイプを知る必要があるのはそれほど良くありません(ageJSONドキュメントののタイプは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を使用する実際の例を見つけるのは非常に困難です。

ヒントはありますか?


1
ではdata->'name'::text'name'文字列を結果ではなくテキストにキャストしています。は有効なJSONリテラルである'25'ため、比較時にエラーが発生しません25。しかし、そうでJennyはありません"Jenny"
chirlu 2016

ありがとう、それが解決策です:-)。と混同'Jenny'しました'"Jenny"'
Golo Roden、2016

回答:


14

これは、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つの演算子->and->>演算子の優先順位混同しているようです。キャスト::はjson(b)演算子よりも強くバインドします。

タイプを動的に把握する

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

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

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

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 ...

上記のselectステートメントの比較のsqlalchemyコア式は何ですか。s = select([issues])。where(issues.c.id == mid).select_from(issues、..... outerjoin(issues.c.data ['type_id'] == mtypes.c.id) )...ここではissue.c.data jsonbデータ型であり、整数型のmtypes.c.idと比較されています
user956424
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.