将任意多行转换为 PostgreSQL 中的列
Turning arbitrarily many rows into columns in PostgreSQL
我在 Postgres 中有一个 table 旨在以非结构化形式捕获信息并重建它。从那个 table 导出数据时,我需要重新应用一些结构,我很挣扎。
目前,我有一个 table 的形式:
lbl | name | value
----|------------|--------
1 | num | 1
1 | colour | "Red"
1 | percentage | 25.0
2 | num | 2
2 | colour | "Green"
2 | percentage | 50.0
3 | num | 3
3 | colour | "Blue"
3 | percentage | 75.0
我需要生成一个 table 这种形式:
lbl | num | colour | percentage
----|-----|---------|------------
1 | 1 | "Red" | 25.0
2 | 2 | "Green" | 50.0
3 | 3 | "Blue" | 75.0
我构建了这个查询:
SELECT lbl,
max(case when name = 'num' then value else '-' end) num,
max(case when name = 'colour' then value else '-' end) colour,
max(case when name = 'percentage' then value else '-' end) percentage
FROM example_table
GROUP BY lbl
查询有效,但我需要扩展它以包括任意数量的名称潜在值。我调查了 crossfunc 但无法让它按我的预期工作。任何帮助将不胜感激。
我在这里设置了一个 sqlfiddle 来帮助启动:http://sqlfiddle.com/#!9/8d3133/6/0
编辑:如果可以的话,我也可以使用 PL/pgSQL。
试试这个
select
tab.ibl,
t1_num.value as "num",
t2_color.value as "colour",
t3_perc.value as "percentage"
from
(
select distinct ibl from your_table order by tab.ibl desc
) tab
left join your_table t1_num on t1_num.ibl = tab.ibl and t1_num.name = 'num'
left join your_table t2_color on t2_color.ibl = tab.ibl and t2_color.name = 'colour'
left join your_table t3_perc on t3_perc.ibl = tab.ibl and t3_perc.name = 'percentage'
Postgres(和其他 RDBMS)中 pivot tables 的主要问题是查询结果的结构(列的数量和名称)不能根据所选数据而变化。一种可能的解决方案是动态创建视图,其结构由数据定义。示例函数基于 table example_table
:
创建视图
create or replace function create_pivot_view()
returns void language plpgsql as $$
declare
list text;
begin
select string_agg(format('jdata->>%1$L "%1$s"', name), ', ')
from (
select distinct name
from example_table
) sub
into list;
execute format($f$
drop view if exists example_pivot_view;
create view example_pivot_view as
select lbl, %s
from (
select lbl, json_object_agg(name, value) jdata
from example_table
group by 1
order by 1
) sub
$f$, list);
end $$;
使用table修改后的函数(可能在触发器中),查询创建的视图:
select create_pivot_view();
select *
from example_pivot_view;
lbl | num | colour | percentage
-----+-----+--------+------------
1 | 1 | Red | 25.0
2 | 2 | Green | 50.0
3 | 3 | Blue | 75.0
(3 rows)
请注意,只有在将新名称添加到 table(或从中删除某些名称)后,才需要重新创建视图(调用函数)。如果不同名称的集合没有改变,您可以查询视图而无需重新创建它。如果经常修改集,创建临时视图将是更好的选择。
您可能还对
感兴趣
我在 Postgres 中有一个 table 旨在以非结构化形式捕获信息并重建它。从那个 table 导出数据时,我需要重新应用一些结构,我很挣扎。
目前,我有一个 table 的形式:
lbl | name | value
----|------------|--------
1 | num | 1
1 | colour | "Red"
1 | percentage | 25.0
2 | num | 2
2 | colour | "Green"
2 | percentage | 50.0
3 | num | 3
3 | colour | "Blue"
3 | percentage | 75.0
我需要生成一个 table 这种形式:
lbl | num | colour | percentage
----|-----|---------|------------
1 | 1 | "Red" | 25.0
2 | 2 | "Green" | 50.0
3 | 3 | "Blue" | 75.0
我构建了这个查询:
SELECT lbl,
max(case when name = 'num' then value else '-' end) num,
max(case when name = 'colour' then value else '-' end) colour,
max(case when name = 'percentage' then value else '-' end) percentage
FROM example_table
GROUP BY lbl
查询有效,但我需要扩展它以包括任意数量的名称潜在值。我调查了 crossfunc 但无法让它按我的预期工作。任何帮助将不胜感激。
我在这里设置了一个 sqlfiddle 来帮助启动:http://sqlfiddle.com/#!9/8d3133/6/0
编辑:如果可以的话,我也可以使用 PL/pgSQL。
试试这个
select
tab.ibl,
t1_num.value as "num",
t2_color.value as "colour",
t3_perc.value as "percentage"
from
(
select distinct ibl from your_table order by tab.ibl desc
) tab
left join your_table t1_num on t1_num.ibl = tab.ibl and t1_num.name = 'num'
left join your_table t2_color on t2_color.ibl = tab.ibl and t2_color.name = 'colour'
left join your_table t3_perc on t3_perc.ibl = tab.ibl and t3_perc.name = 'percentage'
Postgres(和其他 RDBMS)中 pivot tables 的主要问题是查询结果的结构(列的数量和名称)不能根据所选数据而变化。一种可能的解决方案是动态创建视图,其结构由数据定义。示例函数基于 table example_table
:
create or replace function create_pivot_view()
returns void language plpgsql as $$
declare
list text;
begin
select string_agg(format('jdata->>%1$L "%1$s"', name), ', ')
from (
select distinct name
from example_table
) sub
into list;
execute format($f$
drop view if exists example_pivot_view;
create view example_pivot_view as
select lbl, %s
from (
select lbl, json_object_agg(name, value) jdata
from example_table
group by 1
order by 1
) sub
$f$, list);
end $$;
使用table修改后的函数(可能在触发器中),查询创建的视图:
select create_pivot_view();
select *
from example_pivot_view;
lbl | num | colour | percentage
-----+-----+--------+------------
1 | 1 | Red | 25.0
2 | 2 | Green | 50.0
3 | 3 | Blue | 75.0
(3 rows)
请注意,只有在将新名称添加到 table(或从中删除某些名称)后,才需要重新创建视图(调用函数)。如果不同名称的集合没有改变,您可以查询视图而无需重新创建它。如果经常修改集,创建临时视图将是更好的选择。
您可能还对