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 支持不会消失,新添加的内容看起来还不错。




