Jack has demonstrated the way to go. However, I feel there is room for improvement:
DROP SCHEMA x CASCADE;
CREATE SCHEMA x;
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');
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');
CREATE OR REPLACE FUNCTION x.f_dynaquery(int, int, _col text, _type anyelement, OUT col anyelement)
RETURNS SETOF anyelement AS
$body$
BEGIN
RETURN QUERY EXECUTE '
SELECT ' || quote_ident(_col) || '
FROM ' || (
(SELECT schma FROM x.schma WHERE schma_id = $1)
|| '.' ||
(SELECT tbl FROM x.tbl WHERE tbl_id = $2))::regclass;
END;
$body$
LANGUAGE plpgsql STABLE;
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 (actual type matters, not the values)';
Call:
SELECT col FROM x.f_dynaquery(1, 1, 'id', NULL::int);
col
-----
1
2
(2 rows)
SELECT col FROM x.f_dynaquery(1, 2, 'foo', NULL::text);
col
----------------
some text
some more text
(2 rows)
Major points