我已广泛搜索(在Postgres文档和Google和SO上),以查找在表格中的实际JSON列上使用的JSON函数的示例。
这是我的问题:我试图使用jsonb_to_recordset()
从列中的JSON对象数组中提取键值,但是会出现语法错误。当我将对象字面传递给函数时,它可以正常工作:
按字面意思传递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);`
结果:
400MB-PDF.pdf
1000MB-PDF.pdf
它提取键“name”的值。
这是列中的JSON,使用以下方法提取:
select journal.data::jsonb#>>'{context,data,files}'
from journal
where id = 'ap32bbofopvo7pjgo07g';
导致:
[ { "id": 0, "name": "400MB-PDF.pdf", "extension": ".pdf",
"transferId": "ap31fcoqcajjuqml6rng"},
{ "id": 0, "name": "1000MB-PDF.pdf", "extension": ".pdf",
"transferId": "ap31fcoqcajjuqml6rng"}
]
但是当我尝试将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';
我收到语法错误。我尝试了不同的方法,但每次它都抱怨语法错误:
版本: 在x86_64-unknown-linux-gnu上的PostgreSQL 9.4.10,由gcc编译(Ubuntu 4.8.2-19ubuntu1)4.8.2,64位
答案 0 :(得分:5)
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'
请注意,See it working at rextester.com会返回text
类型,而#>
运算符会返回类型jsonb
。由于jsonb_to_recordset
期望jsonb
作为其第一个参数我使用#>
。
{{3}}
答案 1 :(得分:4)
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"}}]');
简单的横向连接查询:
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)
这是困难的部分。请注意,您必须在AS
子句中定义新记录集的外观 - 因为val
数组中的每个元素都是一个JSON对象,其中一个字段名为“outer”,这就是我们给出的内容它。如果您的数组元素包含您感兴趣的多个字段,则以类似的方式声明这些字段。还要注意您的JSON模式需要保持一致:如果数组元素不包含名为“outer”的键,则结果值将为null。
从这里开始,您只需要使用遍历运算符从每个JSON对象中提取所需的特定值。如果我只想要样本数据集中的“内部”值,我会指定select id, r.outer->>'inner'
。由于它已经是JSONB,因此不需要转换。