json_set/jsonb_set で NULL をセットする時の注意

PostgreSQL でのことである。
あるテーブルの JSONB型に、以下のようなJSON値があるとする。

{
  "a":{
     "a1": "Apple",
     "a2": "Lemon"
  }
}

このJSONの"a1" を null にする場合、シングルクォートで括った
文字列 ' null' 指定した以下なら成功する。

UPDATE jbooks SET
jdata = jsonb_set(jdata, '{a,a1}', 'null')
WHERE id = 4

しかし、null をシングルクォートで括らずに

jdata = jsonb_set(jdata, '{a,a1}', null)

としてしまうと、JSONB型のデータ列に null が入ってしまいパスで
指定した値だけを null にできない。

PostgreSQL バージョン13から、jsonb_set_lax と関数が拡張されており、
 jsonb_set(target jsonb, path text, new_value jsonb[, create_missing boolean])
create_missing boolean を省略せずに

jsonb_set_lax( target jsonb, path text
, new_value jsonb
            [, create_if_missing boolean [, null_value_treatment text ]] )

null_value_treatment を指定することで new_value null の時の振る舞いを指定する。

null_value_treatment は、

raise_exception new_value が null ならエラーになり、22004:NULL VALUE NOT ALLOWED になる
use_json_null new_value が null なら null がセットされる
delete_key path で設定された JSONはキーと値が削除される
return_target new_value が null なら変更されない、null でなければそのまま反映される。

だから、

jdata = jsonb_set_lax(jdata, '{a,a1}', null, true, 'use_json_null')

とすれば、期待どおり

{
  "a":{
     "a1": null,
     "a2": "Lemon"
  }
}

になる。
oboe2uran.hatenablog.com
ここで書いたmybatis の mapper は、jsonb_set _lax を使わずに jsonb_set のままでも
null のセットを対応している。

PosetgreSQLのバージョン13 以上の限定になることはないであろう。