2017-01-11 5 views
0

У меня есть сценарий: у меня есть таблица-мастер, в которой хранится имя таблицы и имя столбца, мне нужно построить динамический запрос на основе этого.Динамический запрос Postgres

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. Например, если я передаю Заработку, Имя как подпись и Ид как 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, может ли это использоваться здесь?

Fiddle

EDIT :: Я получил один динамический запрос, который строит союзное заявление, чтобы получить выход, однако проблема в том, я не в состоянии избежать двойных кавычек. Ниже приведен запрос и Ошибка

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

Динамический запрос очень просто - построить все в строковой переменной и использовать 'выполнить yourvariable' в вас работать. Но я думаю, вы должны пересмотреть свою модель данных. Мне кажется слишком сложным задачу, которую вы хотите достичь ... – JosMac

+0

@JosMac Да, это сложно, Однако это не моя модель данных. Я создал фиктивную модель, поскольку я не могу публиковать исходные данные на форумах. Могу ли я использовать несколько имен таблиц в динамическом запросе, иначе я должен пойти для курсора, который будет дорогостоящим, я считаю. –

+1

Вы можете использовать любой запрос в динамическом запросе. Сложное событие CTE со вставками/обновлениями и т. Д. Нет никаких ограничений. – JosMac

ответ

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) 

Однако, вы не можете произвольно ограничивать набор столбцов для извлечения из одной таблицы в другую с помощью этой техники.

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) 
); 

Вы можете избежать случая складывания на д uoting имена:


CREATE TABLE "MasterTable" 
(
    "Id" int primary key, 
    caption varchar(100), 
    dbcolumnname varchar(100), 
    dbtablename varchar(100) 
); 

%I формат спецификатор (внутренне использует quote_ident()) добавляет кавычки в качестве аргумента (при необходимости) , поэтому запрос запрашивает "MasterTable", когда только mastertable присутствует в схеме.

Но это easyer просто избегать СловаРазделенныеРегистром идентификаторов,

Смежные вопросы