在 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

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   │ ░░░░ │
└─────────────────────────────────────────┴───────────┴──────────┴──────┘

据我了解,if jsonb_typeof(some_jsonb_value) = 'null' then ... 就是您想要的。

请注意,现有密钥 i_am_null returns 文本 'null' 和丢失的密钥 foo returns SQL NULL .