暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【译】 PostgreSQL 15 – SQL/JSON 构造函数

原创 Jiang 2022-05-24
1694

SQL/JSON 构造函数

此补丁介绍了 JSON 的 SQL/JSON 标准构造函数:

JSON()
JSON_ARRAY()
JSON_ARRAYAGG()
JSON_OBJECT()
JSON_OBJECTAGG()
复制

在大多数情况下,这些提供了模仿现有的 json/jsonb 函数功能,但是它们也提供了一些有用的附加功能。除了文本输入,JSON() 函数接受 bytea 输入,它将从中解码并构造一个 json 值,其他功能为处理重复键提供了有用的选项和空值。这一系列补丁之后将有一个综合修补文档。

在 Andrew Dunstan 提交另一个补丁之前,该补丁是这个(以及下一个)更改的基础。所以这个想法是 SQL/JSON 是处理 SQL 数据库中的 json 值相关的标准。

PostgreSQL支持 json/jsonb 已经有一段时间了(它是在 2012 年的 Pg 9.2 中添加的!),但现在我们将获得更多支持以标准化方式访问/创建/处理这些,让我们看看我们现在能做什么。

据我所知,所有列出的 JSON*“函数”都会从一些输入中生成 json 值。

我写的是“函数”而不是函数,因为这些不是函数——psql 的 \df JSON* 没有列出它们。更重要的是,我没有看到任何相关文档,所以我能弄清楚的只是基于回归测试。

让我们看一些例子:

=$ select json();
ERROR:  syntax error at or near ")"
LINE 1: select json();
                    ^
=$ select json(null);
 json 
------
 
(1 row)
 
=$ select json(1);
ERROR:  cannot cast type integer to json
LINE 1: select json(1);
                    ^
=$ select json(1.1);
ERROR:  cannot cast type numeric to json
LINE 1: select json(1.1);
                    ^
=$ select json('depesz');
ERROR:  invalid input syntax for type json
DETAIL:  Token "depesz" is invalid.
CONTEXT:  JSON data, line 1: depesz
 
=$ select json('1');
 json 
------
 1
(1 row)
 
=$ select json('"depesz"');
   json   
----------
 "depesz"
(1 row)
 
=$ select json('[1,2,3]');
  json   
---------
 [1,2,3]
(1 row)

复制

好的。所以我通常可以给 json() 一个看起来像 json 的“函数”字面值,因此,我会得到输入到 json 的值。

有趣的是我也可以使用 bytea 值:

=$ select json('\x2264657065737a22'::bytea);
   json   
──────────
 "depesz"
(1 row)

复制

在这一刻,我不能说这是壮观的事情,在具体操作中也会面临一些选择:

  • FORMAT JSON——在没有测试前,我发现除了 JSON 之外的其他值,所以我不知道这是做什么用的。
  • ENCODING X – 这似乎对提供不同(来自服务器)编码的 bytea 值很有用,但我对 ISO-8859-2 数据进行了尝试,但失败了,没有像 iso8859-2、iso88592 或类似的任何值被接受, 并且测试只提到 utf* 变体。

但是有一个有趣的东西可以用于验证:WITH UNIQUE KEYS 或 WITHOUT UNIQUE KEYS。以下是它的工作原理:

=$ select JSON( '{"a": 12, "b": 23}' WITH UNIQUE KEYS );
        json        
--------------------
 {"a": 12, "b": 23}
(1 row)
 
=$ select JSON( '{"a": 12, "b": 23}' WITHOUT UNIQUE KEYS );
        json        
--------------------
 {"a": 12, "b": 23}
(1 row)
 
=$ select JSON( '{"a": 12, "a": 23}' WITH UNIQUE KEYS );
ERROR:  duplicate JSON object key value
 
=$ select JSON( '{"a": 12, "a": 23}' WITHOUT UNIQUE KEYS );
        json        
--------------------
 {"a": 12, "a": 23}
(1 row)
复制

因此,我选择 JSON() 构造函数,并为其提供具有非唯一键的对象数据,但我将添加“WITH UNIQUE KEYS”,它将失败。

好的。让我们切换到下一个:JSON_ARRAY。这其实更有趣。我们可以从简单的开始:

=$ select json_array(1,2,3);
 json_array 
------------
 [1, 2, 3]
(1 row)
复制

然后,我们可以:

=$ select JSON_ARRAY( 1, '12', 'hubert', 'depesz' );
          json_array           
-------------------------------
 [1, "12", "hubert", "depesz"]
(1 row)
复制

或者甚至是做如下操作:

=$ select json_array( 1, 2, json_array('hubert','depesz','lubaczewski'), json('{}') );
                   json_array                    
-------------------------------------------------
 [1, 2, ["hubert", "depesz", "lubaczewski"], {}]
(1 row)
复制

现在,我们也可以让它返回 jsonb 类型:

=$ select json_array( 1, 2, json_array('hubert','depesz','lubaczewski'), json('{}') returning jsonb) \gdesc
   Column   | Type  
------------+-------
 json_array | jsonb
(1 row)
复制

有趣的是,您可以直接选择:

=$ select json_array( select datname from pg_database order by datname returning jsonb );
                        json_array                         
-----------------------------------------------------------
 ["depesz", "pgdba", "postgres", "template0", "template1"]
(1 row)
复制

同样,您现在也可以使用 json_arrayagg:

=$ select json_arrayagg(datname order by datname) from pg_database;
                       json_arrayagg                       
-----------------------------------------------------------
 ["depesz", "pgdba", "postgres", "template0", "template1"]
(1 row)
复制

接下来是 JSON_OBJECT()。这也很有趣:

=$ SELECT JSON_OBJECT( 'a': 123, 'b': json_array(1,2,3));
         json_object          
------------------------------
 {"a" : 123, "b" : [1, 2, 3]}
(1 row)
复制

就像使用 JSON_ARRAY 一样,我可以使用 RETURNING JSONB 来获取 jsonb:

=$ SELECT JSON_OBJECT( relname: relkind returning JSONB) from pg_class limit 1;
      json_object      
-----------------------
 {"pg_statistic": "r"}
(1 row)
复制

就像 JSON_ARRAY 和它的聚合器一样,我们有 JSON_OBJECTAGG:

=$ select JSON_OBJECTAGG( datname: oid) from pg_database;
                                          json_objectagg                                           
---------------------------------------------------------------------------------------------------
 { "postgres" : "5", "pgdba" : "16394", "template1" : "1", "template0" : "4", "depesz" : "16395" }
(1 row)
复制

这看起来很棒,不要误会我的意思:我仍然认为 db 中的 json 经常被滥用,并导致诸如“我如何从 json 字段中的嵌套数组中获取数据”之类的问题提出,这些问题在 IRC、Slack 或 Reddit 上经常出现。

我喜欢基于键/值对制作正确的 jsonb 对象是多么容易,适当引用和处理特殊情况。但是 - json 支持不会消失,新添加的内容看起来还不错。

最后修改时间:2022-05-24 12:02:04
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论