Jack đã chứng minh con đường để đi. Tuy nhiên, tôi cảm thấy có chỗ để cải thiện.
Tôi đặt mọi thứ trong lược đồ x
để thử nghiệm thuận tiện. Thiết lập thử nghiệm:
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');
Hàm cũ (câu trả lời gốc):
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;
Phiên bản sạch hơn với format()
(bản cập nhật 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)';
Gọi:
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
Những điểm chính
Hàm có thể trả về bất kỳ cột nào . Đọc trong hướng dẫn về các loại đa hình và các tham số hàm khai báo .
Bảo vệ chống lại việc tiêm SQL bằng cách sử dụng quote_ident()
và chuyển sangregclass
phiên bản cũ hoặc với phiên bản format()
mới. Liên quan:
Truy xuất tablename bằng truy vấn theo yêu cầu của OP. Ví dụ là truy vấn bởi id
nhưng bất cứ điều gì là có thể.
Đặt tên cho cột trả về, để dễ tham khảo hơn.