在 plpgsql 中识别 jsonb null 的最佳实践
Best practice to identify a jsonb null in plpgsql
我知道之前有人问过这个问题的变体:
- 也许其他人...
我无法从以上链接中收集到的是是否有最佳实践。
考虑以下代码:
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;
$$
有没有更好的方法来判断 i_am_null 是否为 null?
编辑:仅供对此问题感兴趣的人参考,you might be interested in this follow-up question...
您的两个链接答案都包含解决方案,但最好有一个综合答案。
Postgres 是强类型的。它的函数和运算符 return 具体类型。
->
returns jsonb。 .
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 文本和 .
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)
请注意,虽然 jsonb null 只是另一个值,但 SQL null 非常特殊。 Null 不是一个值,它是缺少一个值。 Null equals nothing, not even null。将 null 转换为 jsonb 似乎应该产生 jsonb null,但 SQL 标准要求 null 仅转换为 null 否则将意味着 null 等同于某物。
这就是为什么jsonb null可以转为null,而null不能转为jsonb null的原因。 null::jsonb
为空。这很不方便,但 SQL 标准要求这样做。这是不推荐在 jsonb 和文本之间来回转换的原因之一。
有jsonb_typeof()
函数:
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
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 │ ░░░░ │
└─────────────────────────────────────────┴───────────┴──────────┴──────┘
据我了解,if jsonb_typeof(some_jsonb_value) = 'null' then ...
就是您想要的。
请注意,现有密钥 i_am_null
returns 文本 'null'
和丢失的密钥 foo
returns SQL NULL
.
我知道之前有人问过这个问题的变体:
- 也许其他人...
我无法从以上链接中收集到的是是否有最佳实践。
考虑以下代码:
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;
$$
有没有更好的方法来判断 i_am_null 是否为 null?
编辑:仅供对此问题感兴趣的人参考,you might be interested in this follow-up question...
您的两个链接答案都包含解决方案,但最好有一个综合答案。
Postgres 是强类型的。它的函数和运算符 return 具体类型。
->
returns jsonb。
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 文本和
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)
请注意,虽然 jsonb null 只是另一个值,但 SQL null 非常特殊。 Null 不是一个值,它是缺少一个值。 Null equals nothing, not even null。将 null 转换为 jsonb 似乎应该产生 jsonb null,但 SQL 标准要求 null 仅转换为 null 否则将意味着 null 等同于某物。
这就是为什么jsonb null可以转为null,而null不能转为jsonb null的原因。 null::jsonb
为空。这很不方便,但 SQL 标准要求这样做。这是不推荐在 jsonb 和文本之间来回转换的原因之一。
有jsonb_typeof()
函数:
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
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 │ ░░░░ │
└─────────────────────────────────────────┴───────────┴──────────┴──────┘
据我了解,if jsonb_typeof(some_jsonb_value) = 'null' then ...
就是您想要的。
请注意,现有密钥 i_am_null
returns 文本 'null'
和丢失的密钥 foo
returns SQL NULL
.