PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Scorri le colonne di RECORD

Come spiegato da @Pavel, non è semplicemente possibile attraversare un record, come potresti attraversare un array. Ma ci sono diversi modi per aggirarlo, a seconda delle tue esatte esigenze. In definitiva, poiché vuoi restituire tutti i valori nella stessa colonna, devi eseguirne il cast allo stesso tipo - text è l'ovvio terreno comune, perché esiste una rappresentazione testuale per ogni tipo.

Veloce e sporco

Supponiamo di avere una tabella con un integer , un text e una date colonna.

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

Quindi la soluzione può essere semplice come:

SELECT unnest(string_to_array(trim(t::text, '()'), ','))
FROM   tbl t;

Funziona per le prime due righe, ma non riesce per i casi speciali delle righe 3 e 4.
Puoi risolvere facilmente il problema con le virgole nella rappresentazione del testo:

SELECT unnest(('{' || trim(t::text, '()') || '}')::text[])
FROM   tbl t
WHERE  a < 4;

Questo funzionerebbe bene, ad eccezione della riga 4 che ha virgolette nella rappresentazione del testo. Quelli sono sfuggiti raddoppiandoli. Ma il costruttore dell'array avrebbe bisogno che venissero salvati da \ . Non sono sicuro del motivo per cui questa incompatibilità esiste ...

SELECT ('{' || trim(t::text, '()') || '}') FROM tbl t WHERE a = 4

Rendimento:

{4,""",4,""ex,""",2012-10-04}

Ma avresti bisogno di:

SELECT '{4,"\",4,\"ex,\"",2012-10-04}'::text[];  -- works

Soluzione adeguata

Se conoscessi in anticipo i nomi delle colonne, una soluzione pulita sarebbe semplice:

SELECT unnest(ARRAY[a::text,b::text,c::text])
FROM tbl

Poiché operi su record di tipo noto, puoi semplicemente interrogare il catalogo di 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

Inseriscilo in una funzione con SQL dinamico:

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$;

Chiama:

SELECT unnest_table('tbl') AS val

Resi:

val
-----
1
1text
2012-10-01
2
2text
2012-10-02
3
,3,ex,
2012-10-03
4
",4,"ex,"
2012-10-04

Funziona senza installare moduli aggiuntivi. Un'altra opzione è installare l'estensione hstore e usarla come mostra @Craig.