JSONB演算子の優先順位ではまるとか
JSONBを使った履歴情報integer(履歴情報つきinteger試作 - 日々の記録 別館参照)を作っているときに、ちょっと嵌った現象があったので、備忘のために書いておく。
事象
JSONB演算子 || を使ったときに、以下の事象が起きた(ように勘違いした)。
- 式1 || 式2 だと期待どおりの結果になる
- 式2 || 式1 だとNULLになってしまう
例を示す。
test=# \pset null ぬるぽ Null display is "ぬるぽ". test=# SELECT '{"A":["C","D"]}'::jsonb->'A' || '["X","Y"]'::jsonb ; ?column? ---------------------- ["C", "D", "X", "Y"] (1 row) test=# SELECT '["X","Y"]'::jsonb || '{"A":["C","D"]}'::jsonb->'A' ; ?column? ---------- ぬるぽ (1 row) test=#
原因
まあ、なんということはなく、演算子の優先順位の問題っぽい。
どうやら、連結演算子(||)のほうが キーに依るJSONオブジェクトフィールド取得演算子(->)よりも高いっぽい。
つまり、
SELECT '["X","Y"]'::jsonb || '{"A":["C","D"]}'::jsonb->'A' ;
というのは、
SELECT ( '["X","Y"]'::jsonb || '{"A":["C","D"]}'::jsonb )->'A' ;
というのと同じになる。
["X", "Y", {"A": ["C", "D"]}]
というJSONBオブジェクトに対して、'A'というキーでJSONBオブジェクトを取り出そうとするから、NULLとなってしまうというわけ。
式の見た目からすると、ちょっと直感的ではない気がするけど、そういうことらしい。
PostgrerSQL文書の表4.2 演算子の優先順位(高いものから低いものへ)を見ると、 || も -> も特に規定されていないので、(その他の演算子)と同じ枠になる。
なので、単純に左結合の規則が適用されてしまうと。
言われてみれば当たり前だが、連結演算子(||)って、なんとなく優先順位が低いように思っちゃたのが敗因か。