为每一行生成一个 JSON 值数组

Posted

技术标签:

【中文标题】为每一行生成一个 JSON 值数组【英文标题】:Generate a JSON array of values for each row 【发布时间】:2021-07-22 02:32:22 【问题描述】:

假设以下 CTE:

with mytable as (
    select column1 as foo, column2 as bar, column3 as baz
    from (values
      ('a', 'b', 1),
      ('c', 'd', 2)
    ) v
)

使用array_agg() 输出一个值数组:

select
    array_agg(v)
from mytable v;

-- "(a,b,1)","(c,d,2)"

但令人惊讶的是(至少对我而言),在此数组上使用 to_json() 会将字段名称恢复为每一行的对象

select
    to_json(array_agg(v))
from mytable v;

-- ["foo":"a","bar":"b","baz":1,"foo":"c","bar":"d","baz":2]

我们如何让 PostgreSQL 输出一个数组而不是数组,将每一行呈现为一个值数组?

select
    something(v)
from mytable v;

-- [["a", "b", 1],["c", "d", 2]]

【问题讨论】:

【参考方案1】:

您可以将一行转换为 json,然后取消嵌套键/值对,然后将值聚合回来:

with mytable (foo, bar, baz) as (
  values
    ('a', 'b', 1),
    ('c', 'd', 2)
)
select jsonb_agg(x.vals)
from mytable m
  cross join lateral (
    select jsonb_agg(value order by idx) as vals
    from json_each(row_to_json(m)) with ordinality as t(key,value,idx)
  ) x

如果数组中列值的顺序对您很重要,请务必使用json 转换行。

如果你经常需要这个,你可以把它放到一个函数中。


如果数组中列值的顺序不重要,可以使用 JSON 路径函数:

select jsonb_path_query_array(to_jsonb(m), '$.keyvalue().value')
from mytable m;

【讨论】:

【参考方案2】:

除了 a_horse_with_no_name 的答案之外,我刚刚找到了一种方法来实现这一点,假设列名是已知的:

with mytable as (
    select column1 as foo, column2 as bar, column3 as baz
    from (values
      ('a', 'b', 1),
      ('c', 'd', 2)
    ) v
)

select
    to_json(array_agg(x.vals))
from (
    select
        json_build_array(
            v.foo,
            v.bar,
            v.baz
        ) as vals
    from mytable v
) x
;

-- [["a", "b", 1],["c", "d", 2]]

【讨论】:

以上是关于为每一行生成一个 JSON 值数组的主要内容,如果未能解决你的问题,请参考以下文章

BigQuery - 在数组内部生成时重复的随机数

全局访问由 Json 生成的数组值

golang生成JSON及解析JSON

生成 JSON API 响应后,数字数组索引丢失

Hive查询:匹配列数组的字符串值以生成标志

如何以编程方式填充核心数据存储,为每条记录生成索引