我有透明/交叉的不同数据,例如
给表A
name tag
Bob sport
Bob action
Bob comedy
Tom action
Tom drama
Sue sport
我想要一个将数据转换为
的查询name sport action comedy drama
Bob 1 1 1 0
Tom 0 1 0 1
Sue 1 0 0 0
任意数量n个不同的标签。
如果我在开始之前不知道不同的标签,我将如何使用sql创建此转换。
答案 0 :(得分:2)
一些简单的解决方案适用于某些情况。使用此表(SQL Fiddle现在无法正常工作)
create table a (
name text,
tag text
);
insert into a (name, tag) values
('Bob', 'sport'),
('Bob', 'action'),
('Bob', 'comedy'),
('Tom', 'action'),
('Tom', 'drama'),
('Sue', 'sport');
一个简单的数组聚合,如果它们可以在其他地方拆分
select
name,
array_agg(tag order by tag) as tags,
array_agg(total order by tag) as totals
from (
select name, tag, count(a.name) as total
from
a
right join (
(select distinct tag from a) t
cross join
(select distinct name from a) n
) c using (name, tag)
group by name, tag
) s
group by name
order by 1
;
name | tags | totals
------+-----------------------------+-----------
Bob | {action,comedy,drama,sport} | {1,1,0,1}
Sue | {action,comedy,drama,sport} | {0,0,0,1}
Tom | {action,comedy,drama,sport} | {1,0,1,0}
对于JSON感知客户端,有一组JSON对象
select format(
'{%s:{%s}}',
to_json(name),
string_agg(o, ',')
)::json as o
from (
select name,
format(
'%s:%s',
to_json(tag),
to_json(count(a.name))
) as o
from
a
right join (
(select distinct tag from a) t
cross join
(select distinct name from a) n
) c using (name, tag)
group by name, tag
) s
group by name
;
o
-----------------------------------------------------
{"Bob":{"action":1,"comedy":1,"drama":0,"sport":1}}
{"Sue":{"action":0,"comedy":0,"drama":0,"sport":1}}
{"Tom":{"action":1,"comedy":0,"drama":1,"sport":0}}
或单个JSON对象
select format('{%s}', string_agg(o, ','))::json as o
from (
select format(
'%s:{%s}',
to_json(name),
string_agg(o, ',')
) as o
from (
select name,
format(
'%s:%s',
to_json(tag),
to_json(count(a.name))
) as o
from
a
right join (
(select distinct tag from a) t
cross join
(select distinct name from a) n
) c using (name, tag)
group by name, tag
) s
group by name
) s
;
o
---------------------------------------------------------------------------------------------------------------------------------------------------------
{"Bob":{"action":1,"comedy":1,"drama":0,"sport":1},"Sue":{"action":0,"comedy":0,"drama":0,"sport":1},"Tom":{"action":1,"comedy":0,"drama":1,"sport":0}}