Esta pergunta foi muito mais difícil para resolver do que você pode ter esperado. Sua tentativa com
crosstab()
apontava na direção certa. Mas para atribuir nomes de colunas dinâmicas, você precisa de SQL dinâmico adicionalmente:EXECUTE
em uma função plpgsql.
Altere o tipo de dados da coluna
infos.type
de text
para regtype
para evitar injeção de SQL e outros erros. Por exemplo, você tem o tipo de dados number
, que não é um tipo de dados válido do PostgreSQL. Eu o substituí por numeric
, para que possa funcionar. Você poderia simplifique a tarefa evitando nomes de colunas que precisam de aspas duplas. Como
nume_anterior
em vez de "nume anterior"
. Você pode querer adicionar uma coluna
row_id
para sua tabela info_data
para marcar todos os elementos de uma linha. Você precisa dele para o crosstab()
função, e permite que você ignore colunas com NULL
valores. A crosstab()
função com dois parâmetros pode lidar com colunas ausentes. Sintetizo a coluna ausente com a expressão (d.id-1)/13
abaixo - que funciona para os dados em seu exemplo. Você precisa instalar o módulo adicional tablefunc (uma vez por banco de dados):
CREATE EXTENSION tablefunc;
Encontre explicações e links adicionais nesta resposta relacionada .
Esta função fará o que está procurando:
CREATE OR REPLACE FUNCTION f_mytbl()
RETURNS TABLE (id int
, nume text , prenume text , cnp numeric
, "nume anterior" text, "stare civila" text, cetatenie text
, rezidenta text , adresa text , "tip act" text
, "serie ci" text , "numar ci" text , "data eliberarii" text
, "eliberat de" text)
LANGUAGE plpgsql AS
$BODY$
BEGIN
RETURN QUERY EXECUTE $f$
SELECT *
FROM crosstab(
'SELECT (d.id-1)/13 -- AS row_id
, i.id, d.value
FROM infos i
JOIN info_data d ON d.id_info = i.id
ORDER BY 1, i.id',
'SELECT id
FROM infos
ORDER BY id'
)
AS tbl ($f$ || 'id int,
, nume text , prenume text , cnp numeric
, "nume anterior" text, "stare civila" text, cetatenie text
, rezidenta text , adresa text , "tip act" text
, "serie ci" text , "numar ci" text , "data eliberarii" text
, "eliberat de" text)';
END;
$BODY$;
Ligar:
SELECT * FROM x.mytbl();
Não se confunda com o cotação de dólares .
BTW:eu criei a lista de colunas com esta declaração:
SELECT 'id int,' || string_agg(quote_ident(name) || ' ' || type
,', ' ORDER BY i.id)
FROM infos i;