问题
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
. (Thenull
result should not be confused with a SQLNULL
; 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