Best practice to identify a jsonb null in plpgsql

删除回忆录丶 提交于 2021-01-28 11:47:16

问题


I'm aware that variants of this question have been asked before:

  • Why can't NULL be converted to JSON's null in postgreSQL?
  • Why does JSON null not cast to SQL null in postgres?
  • perhaps others...

What I wasn't able to glean from the above links is whether there is a best practice.

Consider the following code:

DO
$$
DECLARE
  _main_jsonb jsonb = '{"i_am_null": null, "a_string": "null"}';
  _sub_jsonb jsonb;
BEGIN
  SELECT (_main_jsonb->'i_am_null') INTO _sub_jsonb;
  IF _sub_jsonb IS NULL THEN
    RAISE INFO 'This point *not* reached. Bad?';
  END IF;

  -- THIS IS THE PART I AM REALLY INTERESTED IN
  SELECT (_main_jsonb->>'i_am_null')::jsonb INTO _sub_jsonb;
  IF _sub_jsonb IS NULL THEN
    RAISE INFO 'This point *is* reached. Good.';
  END IF;
  -- THIS IS THE PART I AM REALLY INTERESTED IN

  SELECT (_main_jsonb->>'a_string')::jsonb INTO _sub_jsonb;
  IF _sub_jsonb IS NULL THEN
    RAISE INFO 'Bonus points. This point *not* reached. Good.';
  END IF;
END;
$$

Is there a better way to figure out if i_am_null is null?

Edit: FYI to those interested in this question, you might be interested in this follow-up question...


回答1:


Both of your linked answers contain solutions, but it might be good to have an omnibus answer.

Postgres is strongly typed. Its functions and operators return specific types.

-> returns jsonb. Compare it not to SQL null but jsonb null.

test=# select '{"i_am_null": null, "a_string": "null"}'::jsonb->'i_am_null' = 'null'::jsonb;
 ?column? 
----------
 t
(1 row)

test=# select '{"i_am_null": null, "a_string": "null"}'::jsonb->'a_string' = 'null'::jsonb;
 ?column? 
----------
 f
(1 row)

->> returns text and will convert jsonb null into SQL null.

test=# select '{"i_am_null": null, "a_string": "null"}'::jsonb->>'i_am_null' is null;
 ?column? 
----------
 t
(1 row)

test=# select '{"i_am_null": null, "a_string": "null"}'::jsonb->>'a_string' is null;
 ?column? 
----------
 f
(1 row)

Note that while jsonb null is just another value, SQL null is very special. Null is not a value, it is the lack of a value. Null equals nothing, not even null. It might seem like casting null to jsonb should produce jsonb null, but the SQL standard requires that null only casts to null otherwise that would mean null is equivalent to something.

This is why jsonb null can be converted to null, but null is not cast to jsonb null. null::jsonb is null. This is inconvenient, but required by the SQL standard. It is one of the reasons casting back and forth between jsonb and text is not recommended.




回答2:


There is jsonb_typeof() function:

json_typeof ( json ) → text

jsonb_typeof ( jsonb ) → text

Returns the type of the top-level JSON value as a text string. Possible types are object, array, string, number, boolean, and null. (The null result should not be confused with a SQL NULL; see the examples.)

json_typeof('-123.4') → number

json_typeof('null'::json) → null

json_typeof(NULL::json) IS NULL → t

Link

with t(x) as (values('{"i_am_null": null, "a_string": "null"}'::jsonb))
select
    *,
    jsonb_typeof(x->'i_am_null') as "i_am_null",
    jsonb_typeof(x->'a_string') as "a_string",
    jsonb_typeof(x->'foo') as "foo"
from t;

┌─────────────────────────────────────────┬───────────┬──────────┬──────┐
│                    x                    │ i_am_null │ a_string │ foo  │
├─────────────────────────────────────────┼───────────┼──────────┼──────┤
│ {"a_string": "null", "i_am_null": null} │ null      │ string   │ ░░░░ │
└─────────────────────────────────────────┴───────────┴──────────┴──────┘

So if jsonb_typeof(some_jsonb_value) = 'null' then ... is what you want as I understood.

Note that the existing key i_am_null returns the text 'null' and missed key foo returns SQL NULL.



来源:https://stackoverflow.com/questions/65586539/best-practice-to-identify-a-jsonb-null-in-plpgsql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!