【问题标题】:How to convert JSONB array of pair values to rows and columns?如何将 JSONB 对值数组转换为行和列?
【发布时间】:2020-06-25 05:04:06
【问题描述】:

鉴于我有一个带有一对值数组的 jsonb 列:

[1001, 1, 1002, 2, 1003, 3]

我想把每一对变成一行,每对值作为列:

| a    | b |
|------|---|
| 1001 | 1 |
| 1002 | 2 |
| 1003 | 3 |

这样的事情是否可能以一种有效的方式实现?

我发现了一些低效(缓慢)的方法,例如使用 LEAD(),或者使用下一行的值连接同一个表,但查询大约需要 10 分钟。

DDL:

CREATE TABLE products (
  id int not null,
  data jsonb not null
);

INSERT INTO products VALUES (1, '[1001, 1, 10002, 2, 1003, 3]')

DB 小提琴:https://www.db-fiddle.com/f/2QnNKmBqxF2FB9XJdJ55SZ/0

谢谢!

【问题讨论】:

  • 但是给定的示例值没有配对
  • @AkhileshMishra 你这是什么意思?从业务需求的角度来看,它们是“软”配对的。它们在软件工程意义上不是配对的。例如。它不是二维数组。

标签: sql postgresql jsonb


【解决方案1】:

从声明的角度来看,这不是一种优雅的方法,但是您能看看这是否对您更有效吗?

with indexes as (
  select id, generate_series(1, jsonb_array_length(data) / 2) - 1 as idx
    from products
)
select p.id, p.data->>(2 * i.idx) as a, p.data->>(2 * i.idx + 1) as b
  from indexes i
  join products p on p.id = i.id;

【讨论】:

  • 这确实使我们的查询速度更快!限制为 1000 的选择只需要 1.4 秒。以前查询运行了 100 秒。谢谢!
【解决方案2】:

这个查询

SELECT j.data
  FROM products
 CROSS JOIN jsonb_array_elements(data) j(data)

如果您只需要像在演示中那样取消透视查询中的所有元素,则应该运行得更快。

Demo

甚至删除来自products 表的列:

SELECT jsonb_array_elements(data)
  FROM products

如果你需要这样返回

| a    | b |
|------|---|
| 1001 | 1 |
| 1002 | 2 |
| 1003 | 3 |

作为反透视两列,然后使用:

SELECT MAX(CASE WHEN mod(rn,2) = 1 THEN data->>(rn-1)::int END) AS a,
       MAX(CASE WHEN mod(rn,2) = 0 THEN data->>(rn-1)::int END) AS b
  FROM
  (
   SELECT p.data, row_number() over () as rn
     FROM products p
    CROSS JOIN jsonb_array_elements(data) j(data)) q
  GROUP BY ceil(rn/2::float) 
  ORDER BY ceil(rn/2::float)

Demo

【讨论】:

  • 谢谢你,巴巴罗斯的回答。我喜欢它本质上是教育性的。这也是一个优雅的解决方案。不幸的是,结果查询比我们原来的查询慢。它运行了约 7 分钟但没有完成,所以我将其杀死。
猜你喜欢
  • 1970-01-01
  • 2020-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-10
  • 2020-08-30
  • 2021-05-16
  • 1970-01-01
相关资源
最近更新 更多