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

Erstellen Sie eine dynamische Tabelle aus einer Funktion in PostgreSQL

Ihre Lösung ist ein gangbarer Weg. Ich habe Ihre plpgsql-Funktion zur Vereinfachung / Leistung / Lesbarkeit / Sicherheit weitgehend umgeschrieben.

CREATE OR REPLACE FUNCTION f_taxamount()
 RETURNS void AS
$BODY$
DECLARE
    rec record;
BEGIN

    DROP TABLE IF EXISTS tmptable;

    EXECUTE 'CREATE TABLE tmptable (invoiceid integer PRIMARY KEY, '
        || (
           SELECT string_agg(col || ' numeric(9,2) DEFAULT 0', ', ')
           FROM  (
              SELECT quote_ident(lower(replace(taxname,' ','_'))) AS col
              FROM   tbltaxamount
              GROUP  BY 1
              ORDER  BY 1
              ) x
           )
        || ')';

    EXECUTE '
        INSERT INTO tmptable (invoiceid)
        SELECT DISTINCT invoiceid FROM tbltaxamount';

    FOR rec IN
        SELECT taxname, taxamt, invoiceid FROM tbltaxamount ORDER BY invoiceid
    LOOP
        EXECUTE '
            UPDATE tmptable
            SET ' || quote_ident(lower(replace(rec.taxname,' ','_')))
                  || ' = '|| rec.taxamt || ' 
            WHERE invoiceid = ' || rec.invoiceid;
    END LOOP;

END;
$BODY$ LANGUAGE plpgsql;

Dies funktioniert für PostgreSQL 9.1 oder höher.

Für Seite 8.4 oder später ersetzen

SELECT string_agg(col || ' numeric(9,2) DEFAULT 0', ', ')

mit:

SELECT array_to_string(array_agg(col || ' numeric(9,2) DEFAULT 0'), ', ')

Für noch ältere Versionen erstellen Sie dann eine Aggregatfunktion wie diese:

CREATE OR REPLACE FUNCTION f_concat_comma(text, text)
  RETURNS text AS
$BODY$
BEGIN
RETURN ($1 || ', '::text) || $2;
END;
$BODY$
  LANGUAGE plpgsql IMMUTABLE;

CREATE AGGREGATE concat_comma(text) (
  SFUNC=f_concat_comma,
  STYPE=text
);

Und dann schreibe:

SELECT concat_comma(col || ' numeric(9,2) DEFAULT 0')

Auch:

DROP TABLE IF EXISTS tmptable;

Die Klausel "IF EXISTS" wurde mit Version 8.2 eingeführt .
Falls Sie eine noch ältere Version verwenden sollten als das sollten Sie können:

IF EXISTS (
    SELECT *
    FROM   pg_catalog.pg_class
    WHERE  oid = 'tmptable'::regclass
    AND    relkind = 'r')
THEN
    DROP TABLE tmptable;
END IF;
*/

Upgrade!

Sehen Sie sich die Versionierungsrichtlinie des PostgreSQL-Projekts an . Version 8.0.1 ist eine besonders fehlerhafte Version. Ich würde stark raten Ihnen zu einem Upgrade. Wenn Sie nicht auf eine neuere Hauptversion upgraden können, führen Sie aus Sicherheitsgründen zumindest ein Upgrade auf die neueste Point-Release durch, in Ihrem Fall 8.0.26. Dies kann an Ort und Stelle erfolgen, ohne etwas anderes zu ändern.