use*_*122 7 sql postgresql json
我进行了广泛的搜索(在Postgres文档中以及在Google和SO上),以查找表中实际JSON列上使用的JSON函数的示例。
这是我的问题:我尝试使用来从列中的JSON对象数组中提取键值jsonb_to_recordset()
,但会出现语法错误。当我将对象从字面上传递给函数时,它可以正常工作:
从字面上传递JSON:
select *
from jsonb_to_recordset('[
{ "id": 0, "name": "400MB-PDF.pdf", "extension": ".pdf",
"transferId": "ap31fcoqcajjuqml6rng"},
{ "id": 0, "name": "1000MB-PDF.pdf", "extension": ".pdf",
"transferId": "ap31fcoqcajjuqml6rng"}
]') as f(name text);`
Run Code Online (Sandbox Code Playgroud)
结果是:
400MB-PDF.pdf
1000MB-PDF.pdf
Run Code Online (Sandbox Code Playgroud)
它提取键“名称”的值。
这是列中的JSON,使用以下方法提取:
select journal.data::jsonb#>>'{context,data,files}'
from journal
where id = 'ap32bbofopvo7pjgo07g';
Run Code Online (Sandbox Code Playgroud)
导致:
[ { "id": 0, "name": "400MB-PDF.pdf", "extension": ".pdf",
"transferId": "ap31fcoqcajjuqml6rng"},
{ "id": 0, "name": "1000MB-PDF.pdf", "extension": ".pdf",
"transferId": "ap31fcoqcajjuqml6rng"}
]
Run Code Online (Sandbox Code Playgroud)
但是当我尝试将jsonb#>>'{context,data,files}'传递给jsonb_to_recordset()时,如下所示:
select id,
journal.data::jsonb#>>::jsonb_to_recordset('{context,data,files}') as f(name text)
from journal
where id = 'ap32bbofopvo7pjgo07g';
Run Code Online (Sandbox Code Playgroud)
我收到语法错误。我尝试了不同的方法,但是每次它抱怨语法错误时:
版本:x86_64-unknown-linux-gnu上的PostgreSQL 9.4.10,由gcc(Ubuntu 4.8.2-19ubuntu1)4.8.2,64位编译
jsonb_to_recordset
是一个定值函数,只能在特定的地方调用。该FROM
子句就是这样的一个地方,这就是为什么您的第一个示例有效,但该SELECT
子句无效的原因。
为了将您的 JSON 数组变成您可以查询的“表”,您需要使用横向连接。效果很像源记录集上的 foreach 循环,这就是您应用该jsonb_to_recordset
函数的地方。这是一个示例数据集:
create table jstuff (id int, val jsonb);
insert into jstuff
values
(1, '[{"outer": {"inner": "a"}}, {"outer": {"inner": "b"}}]'),
(2, '[{"outer": {"inner": "c"}}]');
Run Code Online (Sandbox Code Playgroud)
一个简单的横向连接查询:
select id, r.*
from jstuff
join lateral jsonb_to_recordset(val) as r("outer" jsonb) on true;
id | outer
----+----------------
1 | {"inner": "a"}
1 | {"inner": "b"}
2 | {"inner": "c"}
(3 rows)
Run Code Online (Sandbox Code Playgroud)
这是最难的部分。请注意,您必须在AS
子句中定义新记录集的外观——因为我们val
数组中的每个元素都是一个 JSON 对象,带有一个名为“outer”的字段,这就是我们给它的。如果您的数组元素包含您感兴趣的多个字段,您可以以类似的方式声明这些字段。另请注意,您的 JSON 架构需要保持一致:如果数组元素不包含名为“outer”的键,则结果值为 null。
从这里开始,您只需要像以前一样使用遍历运算符从每个 JSON 对象中提取您需要的特定值。如果我只想要样本数据集中的“内部”值,我会指定select id, r.outer->>'inner'
. 由于它已经是 JSONB,因此不需要强制转换。
之后的表达式select
必须求值为单个值。由于jsonb_to_recordset
返回的是一组行和列,因此您不能在那里使用它。
解决方案是cross join lateral
,它允许您使用函数将一行扩展为多行。这样select
就可以执行单行操作。例如:
select *
from journal j
cross join lateral
jsonb_to_recordset(j.data#>'{context, data, files}') as d(id int, name text)
where j.id = 'ap32bbofopvo7pjgo07g'
Run Code Online (Sandbox Code Playgroud)
请注意,#>>
运算符返回type text
,而#>
运算符返回type jsonb
。如jsonb_to_recordset
预期的jsonb
那样,我正在使用#>
。
归档时间: |
|
查看次数: |
2554 次 |
最近记录: |