首页 > 解决方案 > 为什么将 JSONB 中的显式“null”提取为文本会产生 SQL“null”?

问题描述

我试图理解PostgreSQL类型null中的处理 s 。jsonb因为

# select 'null'::jsonb is null;
 ?column? 
----------
 f
(1 row)

我假设它们与 SQL 不同null(这是有道理的)-根据手册

SQL NULL 是一个不同的概念。

因此,这两个查询一点也不奇怪:

# select '{"a": 1, "b": null}'::jsonb->'b' is null;
 ?column? 
----------
 f
(1 row)

# select '{"a": 1, "b": null}'::jsonb->'c' is null;
 ?column? 
----------
 t
(1 row)

根据手册

如果 JSON 输入没有正确的结构来匹配请求,则字段/元素/路径提取运算符返回 NULL,而不是失败;例如,如果不存在这样的元素。

然而,惊喜开始的地方是:

# select '{"a": 1, "b": null}'::jsonb->>'b' is null;
 ?column? 
----------
 t
(1 row)

# select '{"a": 1, "b": null}'::jsonb->>'c' is null;
 ?column? 
----------
 t
(1 row)

null后一个我可以理解-我们从提取中得到一个SQL ,然后将其转换nulltext保留它null-我认为按照手册所述->>方式工作

字段/元素/路径提取运算符返回与其左侧输入相同的类型(json 或 jsonb),但指定为返回文本的那些除外,它将值强制为文本。

(顺便说一句,我无法确认将 SQLnull转换为任何其他类型null在 PostgreSQL 中再次产生 - 它是否明确写在某处?)

但前者对我来说是个谜。提取应该给我一个jsonb null,我认为强制转换text应该给我'null'(即,一个字符串说“null”),就像

# select ('null'::jsonb)::text;
 text 
------
 null
(1 row)

但它返回一个正确的 SQL null

为什么呢?

标签: jsonpostgresqlnulljsonb

解决方案


在某种程度上,这是实施者的意见问题;在 JSON 数据类型和 SQL 数据类型之间进行转换时,并不总是可以找到完美的对应关系,尤其是 SQL NULL 非常奇怪。

但是它的实现方式有一定的逻辑。

SELECT (JSONB '{"a": "null"}' -> 'a')::text,
       (JSONB '{"a": null}' -> 'a')::text;

  text  | text 
--------+------
 "null" | null
(1 row)

转换为text始终会产生一个结果,当转换回原始类型时,会产生原始值。这是 PostgreSQL 的设计原则。

所以 JSON 字符串"null"和 JSONnull将被转换为不同的字符串。

现在看看这个:

SELECT JSONB '{"a": "null"}' ->> 'a',
       JSONB '{"a": null}' ->> 'a';

 ?column? | ?column? 
----------+----------
 null     | 
(1 row)

在这里,与上面的转换不同,PostgreSQL 尝试在 SQL 中找到最接近的 JSON 值等价物。您不希望字符串"null"保留其双引号,因为这在 SQL 中将是完全不同的字符串,对吧?

但另一方面,如果"null"并且null在 SQL 中以相同的方式表示,它也会感觉不对,不是吗?

据我所知,JSONnull的意思是“不存在”,这也是 SQL NULL 的含义之一。此外,拥有一个值为 的 JSON 属性null意味着与省略该属性大致相同,不是吗?

因此,尽管有争论的余地,但我认为它的实施方式背后有一些押韵和原因。


推荐阅读