sql >> Database >  >> RDS >> PostgreSQL

Loop door kolommen van RECORD

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.



  1. Is de OraOLEDB-provider in .NET onbetrouwbaar op CLOB-velden?

  2. Waarom zou Oracle.ManagedDataAccess niet werken als Oracle.DataAccess dat wel doet?

  3. PostgreSQL bewaken in een hybride omgeving

  4. Hoe open je een SDF-bestand (SQL Server Compact Edition)?