Postgres加入json数组值

Posted

技术标签:

【中文标题】Postgres加入json数组值【英文标题】:Postgres join on json array values 【发布时间】:2021-06-27 18:40:18 【问题描述】:

我有一张表users如下:

|  id  |        name         |
|  1   |  Marvin Hargraves   |
|  2   |  Lincoln Clayton    |
|  3   |  Frank Pearce       |

还有一个表posts,我在其中获得了带有属性的json列:

|  id   |        attributes       | content |
|  11   | "user_ids":["1", "2"] |  "xyz"  |
|  12   | "user_ids":["1", "3"] |  "xyz"  |

数组中的 ID 引用 users 表中的用户。 我需要显示用户名而不是 ID,例如:

    |  id   |                 users                   |
as an array
    |  11   | ["Marvin Hargraves", "Lincoln Clayton"] |
or string
    |  12   | "Marvin Hargraves, Frank Pearce"        |

我使用的是 PostgreSQL 版本 10。 我试过这个查询:

SELECT p.id, 
  (SELECT array_agg(array[u.name])
   FROM post AS p
   JOIN user u ON u.id = ANY(p.attributes->'user_ids')
   GROUP BY p.id) AS users
FROM post p

但我收到以下错误:

ERROR: op ANY/ALL (array) requires array on right side

【问题讨论】:

json 还是 jsonb?您是只查询 id 和 users,还是实际查询中的更多列? 【参考方案1】:

我建议在LATERAL 子查询中使用ARRAY constructor:

SELECT p.id, j.users
FROM   post p
CROSS  JOIN LATERAL (
   SELECT ARRAY(
      SELECT u.name
      FROM   jsonb_array_elements_text(p.attributes->'user_ids') WITH ORDINALITY j(user_id, ord)
      JOIN   users u ON u.id = j.user_id::int
      ORDER  BY j.ord
      ) AS users
   ) j
;

db小提琴here

请注意,数组中的 null 值将被忽略。

CROSS JOIN 在这种情况下永远不会消除行,因为 ARRAY 构造函数总是返回一行,即使 JSON 数组为空或 NULL。

相关:

How to show all dates from a certain date range in horizontal row? What is the difference between LATERAL JOIN and a subquery in PostgreSQL? PostgreSQL unnest() with element number Why is array_agg() slower than the non-aggregate ARRAY() constructor? How to turn JSON array into Postgres array?

【讨论】:

【参考方案2】:

您将需要使用 jsonb_array_elements_text 解包 jsonb 数组,加入用户,然后将其聚合回来:

SELECT p.id, array_agg(name ORDER BY i) as users
FROM post p
-- Use WITH ORDINALITY to preserve the order of the original array
CROSS JOIN LATERAL jsonb_array_elements_text(p.attributes->'user_ids') WITH ORDINALITY AS j(user_id, i)
JOIN users ON users.id = j.user_id::int
GROUP BY p.id
;

这是fiddle。

【讨论】:

以上是关于Postgres加入json数组值的主要内容,如果未能解决你的问题,请参考以下文章

如何向 JSON 数组值添加键?

Postgres选择包含json的json数组中的位置

在 Postgres JSON 数组中查询

使用 postgres 9.4 将 JSON 元素附加到数组

在 Postgres 11.7 中将 ORDINALITY 添加到扩展的 JSON 数组

如何在 Postgres 中选择一列 json 对象,以便返回的行是 json 数组?