Esta pregunta fue mucho más difícil resolver de lo que esperaba. Tu intento con crosstab()
apuntaba en la dirección correcta. Pero para asignar nombres de columnas dinámicas, necesita además SQL dinámico:EXECUTE
en una función plpgsql.
Cambia el tipo de datos de la columna infos.type
de text
a regtype
para evitar la inyección SQL y otros errores. Por ejemplo, tiene el tipo de datos number
, que no es un tipo de datos de PostgreSQL válido. Lo reemplacé con numeric
, para que pueda funcionar.
podrías simplifique la tarea evitando los nombres de columna que necesitan comillas dobles. Me gusta nume_anterior
en lugar de "nume anterior"
.
Es posible que desee agregar una columna row_id
a su tabla info_data
para marcar todos los elementos de una fila. Lo necesitas para el crosstab()
función, y le permite ignorar las columnas con NULL
valores. La crosstab()
La función con dos parámetros puede ocuparse de las columnas que faltan. Sintetizo la columna que falta con la expresión (d.id-1)/13
a continuación, que funciona para los datos de su ejemplo.
Debe instalar el módulo adicional tablefunc (una vez por base de datos):
CREATE EXTENSION tablefunc;
Encuentre explicaciones y enlaces adicionales en esta respuesta relacionada .
Esta función hará lo que estás buscando:
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$;
Llamar:
SELECT * FROM x.mytbl();
No se confunda con el anidado cotización de dólares .
Por cierto:creé la lista de columnas con esta declaración:
SELECT 'id int,' || string_agg(quote_ident(name) || ' ' || type
,', ' ORDER BY i.id)
FROM infos i;