PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Durchlaufen Sie die Spalten von RECORD

Wie @Pavel erklärte, ist es nicht einfach möglich, einen Datensatz zu durchlaufen, wie Sie ein Array durchlaufen könnten. Es gibt jedoch mehrere Möglichkeiten, dies zu umgehen - je nach Ihren genauen Anforderungen. Da Sie alle Werte in derselben Spalte zurückgeben möchten, müssen Sie sie letztendlich in denselben Typ umwandeln – text ist die offensichtliche Gemeinsamkeit, da es für jeden Typ eine Textdarstellung gibt.

Schnell und schmutzig

Angenommen, Sie haben eine Tabelle mit einer integer , ein text und ein date Säule.

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

Dann kann die Lösung so einfach sein:

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

Funktioniert für die ersten beiden Zeilen, schlägt aber für die Sonderfälle Zeile 3 und 4 fehl.
Sie können das Problem leicht mit Kommas in der Textdarstellung lösen:

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

Dies würde gut funktionieren - mit Ausnahme von Zeile 4, die doppelte Anführungszeichen in der Textdarstellung enthält. Diese werden durch Verdoppelung umgangen. Aber der Array-Konstruktor müsste sie durch \ maskieren . Nicht sicher, warum diese Inkompatibilität da ist ...

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

Ausbeuten:

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

Aber Sie bräuchten:

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

Richtige Lösung

Wenn Sie die Spaltennamen vorher wüssten, wäre eine saubere Lösung einfach:

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

Da Sie mit Datensätzen bekannter Art arbeiten, können Sie einfach den Systemkatalog abfragen:

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

Fügen Sie dies in eine Funktion mit dynamischem SQL ein:

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$;

Aufruf:

SELECT unnest_table('tbl') AS val

Rückgabe:

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

Dies funktioniert ohne Installation zusätzlicher Module. Eine andere Möglichkeit besteht darin, die hstore-Erweiterung zu installieren und sie so zu verwenden, wie @Craig demonstriert.