通过对象键将 SQL JSONB 数组转换为列
Transform SQL JSONB array into columns by object key
我有一个 table 结构如下:
CREATE TABLE artists (artist TEXT UNIQUE, facts JSONB);
INSERT INTO artists (artist, facts)
VALUES ('adele', '[{"type": "full_name", "value": "Adele Laurie"}, {"type": "age", "value": "25"}]');
INSERT INTO artists (artist, facts)
VALUES ('taylor', '[{"type": "age", "value": "25"}, {"type": "last_album", "value": "1989"}]');
有固定数量的事实 "type",但并非每个艺术家都会拥有每个事实。我怎样才能 select 一个结果,每个事实类型都有列,而缺失的事实名称则为 null?
期望的输出:
| artist | full_name | age | last_album |
|--------|---------------|------|------------|
| adele | Adele Laurie | 25 | null |
| taylor | null | 25 | 1989 |
你可以这样做:
select a.artist,
max(case when b.value->>'type' = 'full_name'
then b.value->>'value'
else b.value->>'full_name' end) as full_name,
max(case when b.value->>'type' = 'age'
then b.value->>'value'
else b.value->>'age' end) as age,
max(case when b.value->>'type' = 'last_album'
then b.value->>'value'
else b.value->>'last_album' end) as last_album
from artists a,
json_array_elements(a.facts) b
group by a.artist
order by a.artist
看这里:http://sqlfiddle.com/#!15/e376b/2
在 fiddle 中,我将字段创建为 JSON
,因为 JSONB
类型
不可用
如果您需要添加更多类型,只需像其他类型一样将其添加为案例条件。我想你可以从这里弄明白:)
编辑
即使您更改了格式,此查询也应该可以解决您的问题。刚刚编辑了 fiddle。在这里查看:http://sqlfiddle.com/#!15/1c2b6/2
唯一的区别是 case 语句不需要 else。
这是没有 else 语句的查询
select a.artist,
max(case when b.value->>'type' = 'full_name'
then b.value->>'value' end) as full_name,
max(case when b.value->>'type' = 'age'
then b.value->>'value' end) as age,
max(case when b.value->>'type' = 'last_album'
then b.value->>'value' end) as last_album
from artists2 a,
json_array_elements(a.facts) b
group by a.artist
order by a.artist;
我在此处编辑了 SqlFiddle link。
我会 crosstab()
function. @Eriwn has really good answers 使用这种方法。
示例:
SELECT * FROM crosstab(
'WITH data AS (
SELECT artist,fact
FROM artists a, jsonb_array_elements(a.facts) fact
)
SELECT artist,type,value
FROM data,jsonb_to_record(data.fact) AS x(type text,value text)',
'WITH data AS (
SELECT artist,fact
FROM artists a, jsonb_array_elements(a.facts) fact
)
SELECT DISTINCT type
FROM data,jsonb_to_record(data.fact) AS x(type text,value text)'
) AS ct (artist text,age text,full_name text,last_album TEXT);
结果:
artist | age | full_name | last_album
--------+------+--------------+------------
adele | | Adele Laurie | 25
taylor | 1989 | | 25
(2 rows)
我有一个 table 结构如下:
CREATE TABLE artists (artist TEXT UNIQUE, facts JSONB);
INSERT INTO artists (artist, facts)
VALUES ('adele', '[{"type": "full_name", "value": "Adele Laurie"}, {"type": "age", "value": "25"}]');
INSERT INTO artists (artist, facts)
VALUES ('taylor', '[{"type": "age", "value": "25"}, {"type": "last_album", "value": "1989"}]');
有固定数量的事实 "type",但并非每个艺术家都会拥有每个事实。我怎样才能 select 一个结果,每个事实类型都有列,而缺失的事实名称则为 null?
期望的输出:
| artist | full_name | age | last_album |
|--------|---------------|------|------------|
| adele | Adele Laurie | 25 | null |
| taylor | null | 25 | 1989 |
你可以这样做:
select a.artist,
max(case when b.value->>'type' = 'full_name'
then b.value->>'value'
else b.value->>'full_name' end) as full_name,
max(case when b.value->>'type' = 'age'
then b.value->>'value'
else b.value->>'age' end) as age,
max(case when b.value->>'type' = 'last_album'
then b.value->>'value'
else b.value->>'last_album' end) as last_album
from artists a,
json_array_elements(a.facts) b
group by a.artist
order by a.artist
看这里:http://sqlfiddle.com/#!15/e376b/2
在 fiddle 中,我将字段创建为 JSON
,因为 JSONB
类型
如果您需要添加更多类型,只需像其他类型一样将其添加为案例条件。我想你可以从这里弄明白:)
编辑
即使您更改了格式,此查询也应该可以解决您的问题。刚刚编辑了 fiddle。在这里查看:http://sqlfiddle.com/#!15/1c2b6/2
唯一的区别是 case 语句不需要 else。
这是没有 else 语句的查询
select a.artist,
max(case when b.value->>'type' = 'full_name'
then b.value->>'value' end) as full_name,
max(case when b.value->>'type' = 'age'
then b.value->>'value' end) as age,
max(case when b.value->>'type' = 'last_album'
then b.value->>'value' end) as last_album
from artists2 a,
json_array_elements(a.facts) b
group by a.artist
order by a.artist;
我在此处编辑了 SqlFiddle link。
我会 crosstab()
function. @Eriwn has really good answers 使用这种方法。
示例:
SELECT * FROM crosstab(
'WITH data AS (
SELECT artist,fact
FROM artists a, jsonb_array_elements(a.facts) fact
)
SELECT artist,type,value
FROM data,jsonb_to_record(data.fact) AS x(type text,value text)',
'WITH data AS (
SELECT artist,fact
FROM artists a, jsonb_array_elements(a.facts) fact
)
SELECT DISTINCT type
FROM data,jsonb_to_record(data.fact) AS x(type text,value text)'
) AS ct (artist text,age text,full_name text,last_album TEXT);
结果:
artist | age | full_name | last_album
--------+------+--------------+------------
adele | | Adele Laurie | 25
taylor | 1989 | | 25
(2 rows)