为什么在JSONB中将显式的'null'提取为文本会产生SQL'null'?

为什么在JSONB中将显式的'null'提取为文本会产生SQL'null'?,json,postgresql,null,jsonb,Json,Postgresql,Null,Jsonb,我试图理解PostgreSQL的jsonb类型中的处理nulls。因为 # select 'null'::jsonb is null; ?column? ---------- f (1 row) 我假设它们不同于SQLnulls(这很有意义)- SQLNULL是一个不同的概念 因此,这两个问题一点也不奇怪: # select '{"a": 1, "b": null}'::jsonb->'b' is null; ?column? ---------- f (1 row) #

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

# select 'null'::jsonb is null;
 ?column? 
----------
 f
(1 row)
我假设它们不同于SQL
null
s(这很有意义)-

SQLNULL是一个不同的概念

因此,这两个问题一点也不奇怪:

# 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)
per:

如果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)
后一个我可以理解-我们从提取中得到一个SQL
null
,将
null
强制转换为
text
将其保留为
null
-我假设
->
是这样工作的,如所述

field/element/path提取运算符返回的类型与其左侧输入(json或jsonb)相同,但指定为返回文本的运算符除外,后者将值强制为文本

(顺便说一句,我找不到一个确认,将SQL
null
强制转换为任何其他类型会再次在PostgreSQL中产生
null
——它是明确地写在某个地方的吗?)

但前者对我来说是个谜。提取应该会给我一个
jsonb
null
,我认为对
文本进行转换应该会给我
'null'
(即一个表示“null”的字符串),就像

# select ('null'::jsonb)::text;
 text 
------
 null
(1 row)
但它仍然返回一个正确的SQL
null


为什么会这样?

在某种程度上,这是实施者的意见问题;在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”
和JSON
null
将被转换为不同的字符串

现在看看这个:

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

 ?column? | ?column? 
----------+----------
 null     | 
(1 row)
这里,与上面的cast不同,PostgreSQL试图在SQL中找到与JSON值最接近的等价物。您不希望字符串
“null”
保留其双引号,因为这在SQL中是完全不同的字符串,对吗

但另一方面,如果
“null”
null
在SQL中以相同的方式表示,它也会感觉不正确,不是吗

据我所知,JSON
null
表示“不在那里”,这是sqlnull的含义之一。另外,有一个值为
null
的JSON属性意味着忽略该属性,不是吗


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

它还会有什么回报?它不能返回JSON null,因为操作符显式地根本不返回JSON。它必须应用一些映射,如果不是这样的话,那又怎样呢?好吧,我说过-我期望字符串
'null'
,比如
select('null'::jsonb)::text…非常感谢!这很有趣,现在对我来说很有意义<代码>
这是我的博客文章:
我找不到对你的博客发表评论的方法,所以我把它放在这里:1。有一个“客栈”而不是“in”,2。关于“将
null
强制转换为任何结果都会导致
null
(我在PostgreSQL手册中找不到这方面的证据,但一些实验似乎证实了这一行为,这是完全有道理的):这是SQL标准规定的:“每种数据类型都包含一个特殊的值,称为空值,有时用关键字
null
表示”谢谢!注释页面的链接在左下角,所以请随意留下关于
null
s的注释(我修正了输入错误)。
SELECT (JSONB '{"a": "null"}' -> 'a')::text,
       (JSONB '{"a": null}' -> 'a')::text;

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