Som @Pavel förklarade, är det inte helt enkelt möjligt att gå igenom en post, som du kan korsa en array. Men det finns flera sätt att kringgå det – beroende på dina exakta krav. I slutändan, eftersom du vill returnera alla värden i samma kolumn, måste du casta dem till samma typ - text
är den uppenbara gemensamma grunden, eftersom det finns en textrepresentation för varje typ.
Snabbt och smutsigt
Säg att du har en tabell med ett integer
, en text
och ett date
kolumn.
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
Då kan lösningen vara en enkel som:
SELECT unnest(string_to_array(trim(t::text, '()'), ','))
FROM tbl t;
Fungerar för de två första raderna, men misslyckas för specialfallen på rad 3 och 4.
Du kan enkelt lösa problemet med kommatecken i textrepresentationen:
SELECT unnest(('{' || trim(t::text, '()') || '}')::text[])
FROM tbl t
WHERE a < 4;
Detta skulle fungera bra - förutom rad 4 som har dubbla citattecken i textrepresentationen. De kommer undan genom att fördubbla dem. Men arraykonstruktorn skulle behöva dem escaped av \
. Inte säker på varför denna inkompatibilitet finns där ...
SELECT ('{' || trim(t::text, '()') || '}') FROM tbl t WHERE a = 4
Avkastning:
{4,""",4,""ex,""",2012-10-04}
Men du skulle behöva:
SELECT '{4,"\",4,\"ex,\"",2012-10-04}'::text[]; -- works
Rätt lösning
Om du kände till kolumnnamnen i förväg skulle en ren lösning vara enkel:
SELECT unnest(ARRAY[a::text,b::text,c::text])
FROM tbl
Eftersom du arbetar på poster av välkänd typ kan du bara fråga i systemkatalogen:
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
Lägg detta i en funktion med dynamisk 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$;
Ring:
SELECT unnest_table('tbl') AS val
Returnerar:
val
-----
1
1text
2012-10-01
2
2text
2012-10-02
3
,3,ex,
2012-10-03
4
",4,"ex,"
2012-10-04
Detta fungerar utan att installera ytterligare moduler. Ett annat alternativ är att installera hstore-tillägget och använda det som @Craig visar.