はじめに
json型カラムがあるテーブル同士をUNION
で結合したかったときのお話です。
SQLエラー発生
json型カラムがあるテーブルをUNION
で結合しようとしたらエラーになってしまいました。
等価演算がないよ、っていわれてる
SELECT id, json_contents FROM hoge
UNION
SELECT id, json_contents FROM fuga;
SQLエラー [42883]: ERROR: could not identify an equality operator for type json
回避方法
1. jsonb型にキャストする
json型カラムを、等価演算が使える「jsonb型」にキャストしたらエラーが消えました…!
ただしjsonb型が利用できるのはPostgreSQL9.4以上です。
それ以前のバージョンはtext型にキャストでいけるっぽい(すみません、未確認です)。
SELECT id, json_contents::jsonb FROM hoge
UNION
SELECT id, json_contents::jsonb FROM fuga;
2. UNION ALL使う
UNION
を、等価演算しないUNION ALL
に変えたらエラーが消えました…!
ただし、重複行を除いた結果を抽出したい場合はこの方法は使えません。
重複がないことが自明なテーブル同士を結合する or 重複したところで別に…という場合は、レコードチェックして重複を除く処理がなくなるぶんパフォーマンス的に優位な、UNION ALL
を使うのがよいですね。
SELECT id, json_contents FROM hoge
UNION ALL
SELECT id, json_contents FROM fuga;
さいごに
あらためてUNION
とUNION ALL
の違い、json型について確認です。
UNION と UNION ALL の違いは、重複行の扱いです。 UNION は、重複行を除外します。対して、UNION ALL は重複行を許します。 そのため、重複行を含むテーブルに対しての UNION と UNION ALL では、取得結果が変わります。
(引用元:【SQL】UNION、UNION ALLの使い方 - ITを分かりやすく解説)
表9-1に示されている標準の比較演算子がjsonbで利用可能ですが、jsonではそうではありません。
(引用元:JSON関数と演算子 - PostgreSQL 9.4.5文書)
結局、重複行チェックのため裏で等価演算を実行している部隊(UNION
)に対して、等価演算が使えないやつ(json型)を派遣してしまったゆえ、起きた悲劇であった
…というオチでした。
参考