Този въпрос беше много по-труден за решаване, отколкото може би сте очаквали. Вашият опит с crosstab()
се е насочил в правилната посока. Но за да зададете имена на динамични колони, имате нужда от динамичен SQL в допълнение:EXECUTE
във функция plpgsql.
Променете типа данни на колоната infos.type
от text
до regtype
за предотвратяване на SQL инжектиране и други грешки. Например, имате тип данни number
, което не е валиден тип данни на PostgreSQL. Замених го с numeric
, за да може да работи.
Вие можете опростете задачата, като избягвате имена на колони, които се нуждаят от двойни кавички. Като nume_anterior
вместо "nume anterior"
.
Може да искате да добавите колона row_id
към вашата таблица info_data
за маркиране на всички елементи от един ред. Имате нужда от него за crosstab()
функция и ви позволява да игнорирате колони с NULL
стойности. crosstab()
функция с два параметъра може да се справи с липсващи колони. Синтезирам липсващата колона с израза (d.id-1)/13
по-долу - което работи за данните във вашия пример.
Трябва да инсталирате допълнителния модул tablefunc (веднъж за база данни):
CREATE EXTENSION tablefunc;
Намерете допълнително обяснение и връзки в този свързан отговор .
Тази функция ще направи това, което търсите:
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$;
Обаждане:
SELECT * FROM x.mytbl();
Не се обърквайте от вложеното котиране на долара .
BTW:Създадох списъка с колони с този израз:
SELECT 'id int,' || string_agg(quote_ident(name) || ' ' || type
,', ' ORDER BY i.id)
FROM infos i;