O principal problema com tabelas dinâmicas no Postgres (e outros RDBMS) é que a estrutura (número e nomes das colunas) de um resultado de consulta não pode variar dependendo dos dados selecionados. Uma das soluções possíveis é criar dinamicamente uma visão, cuja estrutura é definida pelos dados. A função de exemplo cria uma visão baseada na tabela
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 $$;
Use a função depois que a tabela for modificada (talvez em um gatilho) e consulte a visualização criada:
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)
Teste no db<>fiddle.
Observe que é necessário recriar uma visão (chamar a função) somente depois que um novo nome for adicionado à tabela (ou algum nome for removido dela). Se o conjunto de nomes distintos não for alterado, você poderá consultar a exibição sem recriá-la. Se o conjunto for modificado com frequência, criar uma visualização temporária seria uma opção melhor.
Você também pode estar interessado em achatar pares de chave/valor agregados de um campo JSONB?