与this previous question类似,对于一对一的映射,我需要一个源和目标中多列的解决方案。
仍在使用Postgres 9.4.4,修改了查询和模式,如下所示:
假设我有两个表Table1
和Table2
:
Create table Table1(col1 int, col2 varchar(100), col3 varchar(100));
Create table Table2(col1 int, col2 varchar(100), col3 varchar(100));
另一个表格Table3
存储了将数据从Table1
迁移到Table2
的公式:
CREATE TABLE Table3 (
tbl_src character varying(200),
col_src character varying(500),
tbl_des character varying(200),
col_des character varying(100),
condition character varying(500)
);
Insert into Table3(tbl_src, col_src, tbl_des, col_des, condition)
VALUES ('Table1','col1','Table2','col1', 'WHERE col1>=1')
, ('Table1','col2','Table2','col2', NULL)
, ('Table1','col3','Table2','col3', NULL);
如何在动态查询中编译此公式并插入目标表?
答案 0 :(得分:0)
动态构建多列的语句的基本查询 - 忽略condition
列:
SELECT format(
'INSERT INTO %I (%s) SELECT %s FROM %I'
, tbl_des
, string_agg(quote_ident(col_des), ', ')
, string_agg(quote_ident(col_src), ', ')
, tbl_src) AS sql
FROM table3
WHERE tbl_des = 'Table2'
AND tbl_src = 'Table1'
GROUP BY tbl_des, tbl_src;
结果:
INSERT INTO "Table2" (col1, col2, col3)
SELECT CASE col1, col2, col3 FROM "Table1"
这假定 单 来源和 单 目标表。或者事情变得更复杂。我添加了WHERE
条件以明确这一点。我添加到my previous answer的区分大小写的注释仍然适用。
以上仍然忽略了condition
。首先,请勿在{{1}}列中添加关键字WHERE
。这只是噪音而没有帮助:
condition
这种方法本质上是不安全的。 INSERT INTO Table3(tbl_src, col_src, tbl_des, col_des, condition)
VALUES ('Table1','col1','Table2','col1', 'col1>=1') -- without WHERE!
, ('Table1', ...
包含需要“按原样”连接的表达式,因此您完全可以接受 SQL注入攻击。您需要确保不受信任的用户无法以任何方式写入condition
以避免这种情况。
在此基础上,假设每个条件仅适用于其各自的列,我们可以通过将列包装在table3
表达式中来解决它:
CASE
生成表格声明:
SELECT format(
'INSERT INTO %I (%s) SELECT %s FROM %I'
, tbl_des
, string_agg(quote_ident(col_des), ', ')
, string_agg(
CASE WHEN condition IS NULL
THEN quote_ident(col_src)
ELSE format('CASE WHEN %s THEN %I END'
, condition, col_src) -- condition is unsafe!
END, ', ')
, tbl_src) AS sql
FROM table3
WHERE tbl_des = 'Table2'
AND tbl_src = 'Table1'
GROUP BY tbl_des, tbl_src;
或者,就像您在稍后的评论中添加的那样,条件可以应用于整行。从逻辑上讲,这是另一个灰色区域。条件存储在特定列中,但适用于整行...
尽管如此,您可以在INSERT INTO "Table2" (col1, col2, col3)
SELECT CASE WHEN col1>=1 THEN col1 END, col2, col3 FROM "Table1"
子句中添加通用条件。
WHERE
条件是AND,并且只有在有条件的情况下才附加SELECT format(
'INSERT INTO %I (%s) SELECT %s FROM %I%s'
, tbl_des
, string_agg(quote_ident(col_des), ', ')
, string_agg(quote_ident(col_src), ', ')
, tbl_src
, ' WHERE ' || string_agg(condition, ' AND ')) AS sql
FROM table3
WHERE tbl_des = 'Table2'
AND tbl_src = 'Table1'
GROUP BY tbl_des, tbl_src;
子句 - 否则生成的NULL值会吞下表达式WHERE
中的已添加关键字
在' WHERE ' || string_agg(condition, ' AND '))
命令或plpgsql函数中使用它,就像我之前的答案中指示的那样动态执行:
基本plpgsql函数:
DO