我有一个场景,我有一个存储db表名和列名的主表,我需要根据它建立动态查询。
CREATE TABLE MasterTable
(
Id int primary key,
caption varchar(100),
dbcolumnname varchar(100),
dbtablename varchar(100)
);
CREATE TABLE Engineers
(
Id int primary key,
Name varchar(100),
Salary BigInt
);
CREATE TABLE Executives
(
Id int primary key,
Name varchar(100),
Salary BigInt
);
CREATE TABLE Manager
(
Id int primary key,
Name varchar(100),
Salary BigInt
);
INSERT INTO Manager(Id, Name, Salary)
VALUES(1, 'Manager 1', 6000000);
INSERT INTO Executives(Id, Name, Salary)
VALUES(1, 'Executive 1', 6000000);
INSERT INTO Engineers(Id, Name, Salary)
VALUES(1, 'Engineer 1', 6000000);
INSERT INTO MasterTable(Id, caption, dbcolumnname, dbtablename)
VALUES (1, 'Name', 'name', 'Engineers');
INSERT INTO MasterTable(Id, caption, dbcolumnname, dbtablename)
VALUES (2, 'Name', 'name', 'Manager');
INSERT INTO MasterTable(Id, caption, dbcolumnname, dbtablename)
VALUES (3, 'Name', 'name', 'Executives');
INSERT INTO MasterTable(Id, caption, dbcolumnname, dbtablename)
VALUES (4, 'Salary', 'Salary', 'Engineers');
INSERT INTO MasterTable(Id, caption, dbcolumnname, dbtablename)
VALUES (5, 'Salary', 'Salary', 'Manager');
INSERT INTO MasterTable(Id, caption, dbcolumnname, dbtablename)
VALUES (6, 'Salary', 'Salary', 'Executives');
我想构建一个存储过程,该过程接受标题和Id,并根据dbcolumnname和dbtablename返回结果。例如,如果我将Salary,Name作为标题并将Id作为1传递,则存储过程应该是dbcolumn和dbtable的查询,如下所示。
Select Id as ID, name as Value from Engineers
UNION
Select Id as ID, name as Value from Manager
UNION
Select Id as ID, name as Value from Executives
UNION
Select Id as ID, Salary as Value from Executives
UNION
Select Id as ID, Salary as Value from Engineers
UNION
Select Id as ID, Salary as Value from Manager
我听说过动态sql,可以在这里使用吗?
编辑::我有一个动态查询,它构建了union语句来获取输出,但问题是我无法转义双引号。以下是查询和错误
Query :
DO
$BODY$
BEGIN
EXECUTE string_agg(
format('SELECT %I FROM %I', dbcolumnname, dbtablename),
' UNION ')
FROM MasterTable;
END;
$BODY$;
Error:
ERROR: relation "Engineers" does not exist
LINE 1: SELECT name FROM "Engineers" UNION SELECT name FROM "Manager...
答案 0 :(得分:0)
我想建议另一种方法来实现你想要的。也就是说,使用PostgreSQL继承机制。
例如:
CREATE TABLE ParentTable (
Id int,
Name varchar(100),
Salary BigInt
);
ALTER TABLE Engineers INHERIT ParentTable;
ALTER TABLE Executives INHERIT ParentTable;
ALTER TABLE Manager INHERIT ParentTable;
SELECT Id, Salary AS value FROM ParentTable
UNION
SELECT Id, Name AS value FROM ParentTable;
现在,如果您想使用MasterTable来限制所使用的表集,您可以按如下方式执行:
SELECT Id, Name AS value
FROM ParentTable
INNER JOIN pg_class ON parenttable.tableoid = pg_class.oid
INNER JOIN MasterTable ON LOWER(dbtablename) = LOWER(relname)
UNION
SELECT Id, Salary AS value
FROM ParentTable
INNER JOIN pg_class ON parenttable.tableoid = pg_class.oid
INNER JOIN MasterTable ON LOWER(dbtablename) = LOWER(relname)
但是,您不能使用此技术任意限制要从一个表检索到另一个表的列集。
答案 1 :(得分:0)
表名和列名在SQL中不区分大小写,除非在双引号中引用。 Postgres通过将不带引号的标识符折叠为小写来实现此目的。
所以,你的DDL:
CREATE TABLE MasterTable
(
Id int primary key,
caption varchar(100),
dbcolumnname varchar(100),
dbtablename varchar(100)
);
将由Postgres解释为
CREATE TABLE mastertable
(
id int primary key,
caption varchar(100),
dbcolumnname varchar(100),
dbtablename varchar(100)
);
您可以通过引用名称来避免案例折叠:
CREATE TABLE "MasterTable"
(
"Id" int primary key,
caption varchar(100),
dbcolumnname varchar(100),
dbtablename varchar(100)
);
%I
格式说明符(内部使用 quote_ident())为其参数添加引号(如果需要)
,因此当架构中仅存在"MasterTable"
时,查询会询问mastertable
。
但是,避免使用MixedCase标识符更容易,