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

Gå gennem kolonnerne i RECORD

Som @Pavel forklarede, er det ikke bare muligt at krydse en post, ligesom du kunne krydse en matrix. Men der er flere måder at undgå det på – afhængigt af dine præcise krav. I sidste ende, da du vil returnere alle værdier i samme kolonne, skal du caste dem til den samme type - text er det åbenlyse fælles grundlag, fordi der er en tekstrepræsentation for hver type.

Hurtig og beskidt

Lad os sige, du har en tabel med et integer , en text og en date kolonne.

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
 

Så kan løsningen være en simpel som:

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

Fungerer for de første to rækker, men fejler i specialtilfældene af række 3 og 4.
Du kan nemt løse problemet med kommaer i tekstgengivelsen:

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

Dette ville fungere fint - bortset fra linje 4, som har dobbelte anførselstegn i tekstgengivelsen. Dem undslipper man ved at fordoble dem. Men array-konstruktøren ville have brug for dem undslippet af \ . Ikke sikker på, hvorfor denne inkompatibilitet er der ...

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

Udbytter:

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

Men du skal bruge:

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

Korrekt løsning

Hvis du kendte kolonnenavnene på forhånd, ville en ren løsning være enkel:

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

Da du opererer på optegnelser af velkendt type, kan du bare forespørge i systemkataloget:

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
 

Sæt dette 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 til:

SELECT unnest_table('tbl') AS val
 

Returnerer:

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

Dette fungerer uden at installere yderligere moduler. En anden mulighed er at installere hstore-udvidelsen og bruge den som @Craig demonstrerer.



  1. Tilføj førende og efterfølgende nuller i SQL Server

  2. Hvordan tilføjer man en ny kolonne i en tabel efter 2. eller 3. kolonne i tabellen ved hjælp af postgres?

  3. Sådan fungerer LOG() i MariaDB

  4. pgFincore 1.2, en PostgreSQL-udvidelse