Jack hat den Weg gezeigt. Ich bin jedoch der Meinung, dass es Raum für Verbesserungen gibt.
Ich platziere alles im Schema x
für bequeme Tests. Versuchsaufbau:
DROP SCHEMA x CASCADE;
CREATE SCHEMA x;
-- meta tables for schema and table name
CREATE TABLE x.schma(schma_id int, schma text);
INSERT INTO x.schma VALUES (1, 'x');
CREATE TABLE x.tbl(tbl_id int, tbl text);
INSERT INTO x.tbl VALUES (1, 't1'), (2, 't2');
-- dummy tables to be used in example query:
CREATE TABLE x.t1(id int);
INSERT INTO x.t1 VALUES (1),(2);
CREATE TABLE x.t2(foo text);
INSERT INTO x.t2 VALUES ('some text'), ('some more text');
Alte Funktion (ursprüngliche Antwort):
CREATE OR REPLACE FUNCTION x.f_dynaquery_old(int, int, _col text, _type anyelement, OUT col anyelement)
RETURNS SETOF anyelement AS
$func$
BEGIN
RETURN QUERY EXECUTE '
SELECT ' || quote_ident(_col) || '
FROM ' || (
(SELECT schma FROM schma WHERE schma_id = $1) || '.' ||
(SELECT tbl FROM tbl WHERE tbl_id = $2))::regclass;
END
$func$ LANGUAGE plpgsql;
Sauberere Version mit format()
(Update 2017):
CREATE OR REPLACE FUNCTION x.f_dynaquery(_schma_id int, _tbl_id int
, _col text, _type anyelement)
RETURNS TABLE(col anyelement) AS
$func$
BEGIN
RETURN QUERY EXECUTE format(
'SELECT %I FROM %I.%I'
, _col
, (SELECT schma FROM schma WHERE schma_id = _schma_id)
, (SELECT tbl FROM tbl WHERE tbl_id = _tbl_id)
);
END
$func$ LANGUAGE plpgsql;
COMMENT ON FUNCTION x.f_dynaquery(int, int, text, anyelement)
IS 'Query any column from a dynamically assembled tablename.
$1 .. id of schema
$2 .. id of table
$3 .. name of column
$4 .. type of column (only data type matters, not the value)';
Anruf:
SELECT col FROM x.f_dynaquery(1, 1, 'id', NULL::int);
col
-----
1
2
SELECT col FROM x.f_dynaquery(1, 2, 'foo', NULL::text);
col
----------------
some text
some more text
Hauptpunkte
Die Funktion kann jede Spalte eines beliebigen Typs zurückgeben . Lesen Sie im Handbuch über polymorphe Typen und das Deklarieren von Funktionsparametern .
Verteidigen gegen SQL - Injection durch die Verwendung quote_ident()
und Gießenregclass
in der alten Version oder mit format()
in dem neuen. Verbunden:
Rufen Sie den Tabellennamen per Abfrage ab, wenn OP angefordert wird. Beispiel ist die Abfrage von, id
aber alles ist möglich.
Benennen Sie die zurückgegebene Spalte, damit Sie leichter darauf verweisen können.
Sie benötigen dynamisches SQL - vielleicht so etwas:
Ich gehe davon aus, dass jede Tabelle in jedem Schema vorhanden ist, wie die Frage impliziert
quelle