[英]How to convert JSON Array of Arrays to columns and rows
我从 JSON 格式的API中提取数据,格式类似于下面的示例数据。 基本上每个“行”都是一个值数组。 API 文档预先定义了列及其类型。 例如,我知道 col1 是一个 varchar,而 col2 是一个 int。
CREATE TEMP TABLE dat (data json);
INSERT INTO dat
VALUES ('{"COLUMNS":["col1","col2"],"DATA":[["a","1"],["b","2"]]}');
我想在 PostgreSQL 9.3 中转换它,这样我最终得到:
col1 | col2
------------
a | 1
b | 2
使用json_array_elements
我可以:
SELECT json_array_elements(data->'DATA')
FROM dat
json_array_elements
json
---------
["a","1"]
["b","2"]
但后来我不知道如何将 JSON 数组转换为 PostgreSQL 数组,以便我可以执行类似unnest(ARRAY['a','1'])
得到这样的结果
col1 | col2
------------
a | 1
b | 2
将需要一堆动态SQL,因为您事先不知道列的类型,也不知道列名。
您可以使用以下内容解压缩 json:
SELECT
json_array_element_text(colnames, colno) AS colname,
json_array_element_text(colvalues, colno) AS colvalue,
rn,
idx,
colno
FROM (
SELECT
data -> 'COLUMNS' AS colnames,
d AS colvalues,
rn,
row_number() OVER () AS idx
FROM (
SELECT data, row_number() OVER () AS rn FROM dat
) numbered
cross join json_array_elements(numbered.data -> 'DATA') d
) elements
cross join generate_series(0, json_array_length(colnames) - 1) colno;
产生一个结果集,如:
colname | colvalue | rn | idx | colno
---------+----------+----+-----+-------
col1 | a | 1 | 1 | 0
col2 | 1 | 1 | 1 | 1
col1 | b | 1 | 2 | 0
col2 | 2 | 1 | 2 | 1
(4 rows)
然后,您可以将其用作 tablefunc 模块中交叉表函数的输入,例如:
SELECT * FROM crosstab('
SELECT
to_char(rn,''00000000'')||''_''||to_char(idx,''00000000'') AS rowid,
json_array_element_text(colnames, colno) AS colname,
json_array_element_text(colvalues, colno) AS colvalue
FROM (
SELECT
data -> ''COLUMNS'' AS colnames,
d AS colvalues,
rn,
row_number() OVER () AS idx
FROM (
SELECT data, row_number() OVER () AS rn FROM dat
) numbered
cross join json_array_elements(numbered.data -> ''DATA'') d
) elements
cross join generate_series(0, json_array_length(colnames) - 1) colno;
') results(rowid text, col1 text, col2 text);
生产:
rowid | col1 | col2
---------------------+------+------
00000001_ 00000001 | a | 1
00000001_ 00000002 | b | 2
(2 rows)
此处不保留列名。
如果您在 9.4 上,您可以避免row_number()
调用并使用WITH ORDINALITY
,使其更清晰。
由于您显然事先知道列数及其类型,因此可以大大简化查询。
SELECT
col1, col2
FROM (
SELECT
rn,
row_number() OVER () AS idx,
elem ->> 0 AS col1,
elem ->> 1 :: integer AS col2
FROM (
SELECT data, row_number() OVER () AS rn FROM dat
) numbered
cross join json_array_elements(numbered.data -> 'DATA') elem
ORDER BY 1, 2
) x;
结果:
col1 | col2
------+------
a | 1
b | 2
(2 rows)
WITH ORDINALITY
使用 9.4 如果您使用的是 9.4,则可以使用WITH ORDINALITY
使其更干净:
SELECT
col1, col2
FROM (
SELECT
elem ->> 0 AS col1,
elem ->> 1 :: integer AS col2
FROM
dat
CROSS JOIN
json_array_elements(dat.data -> 'DATA') WITH ORDINALITY AS elements(elem, idx)
ORDER BY idx
) x;
这段代码对我来说很好用,也许对某人有用。
select to_json(array_agg(t))
from (
select text, pronunciation,
(
select array_to_json(array_agg(row_to_json(d)))
from (
select part_of_speech, body
from definitions
where word_id=words.id
order by position asc
) d
) as definitions
from words
where text = 'autumn'
) t
学分: https : //hashrocket.com/blog/posts/faster-json-generation-with-postgresql
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.