在 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 中将多列合并为一列

如何在 Postgres 中将一个类型拆分为多个列?

如何在 Postgres-XL 中将 SEQUENCE 设置为 DEFAULT?

如何在python中将单引号存储到postgres [重复]

如何在 Heroku 中将 Kafka 连接到 Postgres