在 Postgres 11.7 中将 ORDINALITY 添加到扩展的 JSON 数组
Posted
技术标签:
【中文标题】在 Postgres 11.7 中将 ORDINALITY 添加到扩展的 JSON 数组【英文标题】:Add ORDINALITY to expanded JSON array in Postgres 11.7 【发布时间】:2020-05-10 04:21:08 【问题描述】:我正在获取两个 JSONB 数组,将它们解包并组合结果。我正在尝试将 WITH ORDINALITY
添加到 JSON 数组解包中。我一直无法弄清楚如何添加WITH ORDINALITY
。出于某种原因,我在 Postgres 11 的 JSON 工具的文档中找不到 WITH ORDINALITY
:
https://www.postgresql.org/docs/11/functions-json.html
我见过使用jsonb_array_elements....WITH ORDINALITY
的示例,但无法让它工作。一、基于Postgres数组的函数式示例:
WITH
first AS (
SELECT * FROM
UNNEST (ARRAY['Charles','Jane','George','Percy']) WITH ORDINALITY AS x(name_, index)
),
last AS (
SELECT * FROM
UNNEST (ARRAY['Dickens','Austen','Eliot']) WITH ORDINALITY AS y(name_, index)
)
SELECT first.name_ AS first_name,
last.name_ AS last_name
FROM first
JOIN last ON (last.index = first.index)
这给出了所需的输出:
first_name last_name
Charles Dickens
Jane Austen
George Eliot
我正在使用ORDINALITY
索引来创建JOIN
,因为我正在组合两个列表以进行成对比较。我可以假设我的列表大小相同。
但是,我的输入将是 JSON 数组,而不是 Postgres 数组。我已经使用jsonb_to_recordset
进行了拆包工作,但还没有让序数生成工作。这是一个正确完成拆包部分的示例:
DROP FUNCTION IF EXISTS tools.try_ordinality (jsonb, jsonb);
CREATE OR REPLACE FUNCTION tools.try_ordinality (
base_jsonb_in jsonb,
comparison_jsonb_in jsonb)
RETURNS TABLE (
base_text citext,
base_id citext,
comparison_text citext,
comparison_id citext)
AS $BODY$
BEGIN
RETURN QUERY
WITH
base_expanded AS (
select *
from jsonb_to_recordset (
base_jsonb_in)
AS base_unpacked (text citext, id citext)
),
comparison_expanded AS (
select *
from jsonb_to_recordset (
comparison_jsonb_in)
AS comparison_unpacked (text citext, id citext)
),
combined_lists AS (
select base_expanded.text AS base_text,
base_expanded.id AS base_id,
comparison_expanded.text AS comparison_text,
comparison_expanded.id AS comparison_id
from base_expanded,
comparison_expanded
)
select *
from combined_lists;
END
$BODY$
LANGUAGE plpgsql;
select * from try_ordinality (
'[
"text":"Fuzzy Green Bunny","id":"1",
"text":"Small Gray Turtle","id":"2"
]',
'[
"text":"Red Large Special","id":"3",
"text":"Blue Small","id":"4",
"text":"Green Medium Special","id":"5"
]'
);
但那是CROSS JOIN
base_text base_id comparison_text comparison_id
Fuzzy Green Bunny 1 Red Large Special 3
Fuzzy Green Bunny 1 Blue Small 4
Fuzzy Green Bunny 1 Green Medium Special 5
Small Gray Turtle 2 Red Large Special 3
Small Gray Turtle 2 Blue Small 4
Small Gray Turtle 2 Green Medium Special 5
我追求的是只有两行的成对结果:
Fuzzy Green Bunny 1 Red Large Special 3
Small Gray Turtle 2 Blue Small 4
我已经尝试切换到jsonb_array_elements
,就像在这个 sn-p 中一样:
WITH
base_expanded AS (
select *
from jsonb_array_elements (
base_jsonb_in)
AS base_unpacked (text citext, id citext)
),
我回来了
ERROR: a column definition list is only allowed for functions returning "record"
有没有一种直接的方法来获取解压缩的 JSON 数组的序数?在 Postgres 数组上使用 UNNEST
非常简单。
我很高兴得知我搞砸了语法。
如果有帮助,我可以CREATE TYPE
。
如果操作简单,我可以转换为 Postgres 数组。
感谢您的任何建议。
【问题讨论】:
WITH ORDINALITY 适用于任何集合返回函数。 JSON 确实具有您可以使用的集合返回函数,但在那里记录它会很奇怪,因为它在那里的操作方式与非 JSON 集合返回函数的操作方式相同。 【参考方案1】:你做的完全一样。
with first as (
select *
from jsonb_array_elements('[
"text":"Fuzzy Green Bunny","id":"1",
"text":"Small Gray Turtle","id":"2"
]'::jsonb) with ordinality as f(element, idx)
), last as (
select *
from jsonb_array_elements('[
"text":"Red Large Special","id":"3",
"text":"Blue Small","id":"4",
"text":"Green Medium Special","id":"5"
]'::jsonb) with ordinality as f(element, idx)
)
SELECT first.element ->> 'text' AS first_name,
last.element ->> 'text' AS last_name
FROM first
JOIN last ON last.idx = first.idx
【讨论】:
以上是关于在 Postgres 11.7 中将 ORDINALITY 添加到扩展的 JSON 数组的主要内容,如果未能解决你的问题,请参考以下文章
在 Postgres 中将时间戳截断为 5 分钟的最快方法是啥?
如何在 Postgres-XL 中将 SEQUENCE 设置为 DEFAULT?