Como explicó @Pavel, no es simplemente posible atravesar un registro, como podría atravesar una matriz. Pero hay varias formas de evitarlo, dependiendo de sus requisitos exactos. En última instancia, dado que desea devolver todos los valores en la misma columna, debe convertirlos en el mismo tipo:text
es el terreno común obvio, porque hay una representación de texto para cada tipo.
Rápido y sucio
Digamos que tienes una tabla con un integer
, un text
y una date
columna.
CREATE TEMP TABLE tbl(a int, b text, c date);
INSERT INTO tbl VALUES
(1, '1text', '2012-10-01')
,(2, '2text', '2012-10-02')
,(3, ',3,ex,', '2012-10-03') -- text with commas
,(4, '",4,"ex,"', '2012-10-04') -- text with commas and double quotes
Entonces la solución puede ser tan simple como:
SELECT unnest(string_to_array(trim(t::text, '()'), ','))
FROM tbl t;
Funciona para las dos primeras filas, pero falla para los casos especiales de las filas 3 y 4.
Puede resolver fácilmente el problema con comas en la representación del texto:
SELECT unnest(('{' || trim(t::text, '()') || '}')::text[])
FROM tbl t
WHERE a < 4;
Esto funcionaría bien, excepto por la línea 4 que tiene comillas dobles en la representación del texto. Esos se escapan doblándolos. Pero el constructor de la matriz los necesitaría escapados por \
. No estoy seguro de por qué existe esta incompatibilidad...
SELECT ('{' || trim(t::text, '()') || '}') FROM tbl t WHERE a = 4
Rendimientos:
{4,""",4,""ex,""",2012-10-04}
Pero necesitarías:
SELECT '{4,"\",4,\"ex,\"",2012-10-04}'::text[]; -- works
Solución adecuada
Si supiera los nombres de las columnas de antemano, una solución limpia sería simple:
SELECT unnest(ARRAY[a::text,b::text,c::text])
FROM tbl
Dado que opera en registros de tipo bien conocido, solo puede consultar el catálogo del sistema:
SELECT string_agg(a.attname || '::text', ',' ORDER BY a.attnum)
FROM pg_catalog.pg_attribute a
WHERE a.attrelid = 'tbl'::regclass
AND a.attnum > 0
AND a.attisdropped = FALSE
Ponga esto en una función con SQL dinámico:
CREATE OR REPLACE FUNCTION unnest_table(_tbl text)
RETURNS SETOF text LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE '
SELECT unnest(ARRAY[' || (
SELECT string_agg(a.attname || '::text', ',' ORDER BY a.attnum)
FROM pg_catalog.pg_attribute a
WHERE a.attrelid = _tbl::regclass
AND a.attnum > 0
AND a.attisdropped = false
) || '])
FROM ' || _tbl::regclass;
END
$func$;
Llamar:
SELECT unnest_table('tbl') AS val
Devoluciones:
val
-----
1
1text
2012-10-01
2
2text
2012-10-02
3
,3,ex,
2012-10-03
4
",4,"ex,"
2012-10-04
Esto funciona sin instalar módulos adicionales. Otra opción es instalar la extensión hstore y usarla como demuestra @Craig.