sql >> Databasteknik >  >> RDS >> PostgreSQL

Gå igenom kolumner i RECORD

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.



  1. Hur man importerar en CSV-fil till en MySQL-tabell

  2. syntaxfel med uppdateringsfråga när du går med i någon tabell

  3. Vikten av baslinjer

  4. Oracle UNION Operatör förklaras