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.