Zoals @Pavel uitlegde, is het niet zomaar mogelijk om een record te doorkruisen, zoals je een array zou kunnen doorkruisen. Maar er zijn verschillende manieren om dit te omzeilen - afhankelijk van uw exacte vereisten. Omdat u uiteindelijk alle waarden in dezelfde kolom wilt retourneren, moet u ze naar hetzelfde type casten - text
is de voor de hand liggende raakvlakken, omdat er voor elk type een tekstweergave is.
Snel en vuil
Stel, je hebt een tabel met een integer
, een text
en een date
kolom.
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
Dan kan de oplossing eenvoudig zijn als:
SELECT unnest(string_to_array(trim(t::text, '()'), ','))
FROM tbl t;
Werkt voor de eerste twee rijen, maar mislukt voor de speciale gevallen van rij 3 en 4.
U kunt het probleem eenvoudig oplossen met komma's in de tekstweergave:
SELECT unnest(('{' || trim(t::text, '()') || '}')::text[])
FROM tbl t
WHERE a < 4;
Dit zou prima werken - behalve regel 4 die dubbele aanhalingstekens heeft in de tekstweergave. Die worden ontsnapt door ze te verdubbelen. Maar de array-constructor zou ze moeten escapen door \
. Ik weet niet zeker waarom deze incompatibiliteit er is ...
SELECT ('{' || trim(t::text, '()') || '}') FROM tbl t WHERE a = 4
Opbrengsten:
{4,""",4,""ex,""",2012-10-04}
Maar je hebt nodig:
SELECT '{4,"\",4,\"ex,\"",2012-10-04}'::text[]; -- works
Goede oplossing
Als u de kolomnamen van tevoren wist, zou een schone oplossing eenvoudig zijn:
SELECT unnest(ARRAY[a::text,b::text,c::text])
FROM tbl
Aangezien u werkt met records van het bekende type, kunt u gewoon de systeemcatalogus raadplegen:
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
Zet dit in een functie met dynamische SQL:
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$;
Bel:
SELECT unnest_table('tbl') AS val
Retourneren:
val
-----
1
1text
2012-10-01
2
2text
2012-10-02
3
,3,ex,
2012-10-03
4
",4,"ex,"
2012-10-04
Dit werkt zonder extra modules te installeren. Een andere optie is om de hstore-extensie te installeren en deze te gebruiken zoals @Craig laat zien.