sql >> Base de Datos >  >> RDS >> PostgreSQL

Recorra las columnas de RECORD

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.