当前位置: 首页 > 面试题库 >

如何从动态查询中插入具有多列的表?

金昂熙
2023-03-14
问题内容

与先前 的一对一映射问题 类似,我需要一个针对源和目标中多列的解决方案。
仍可与Postgres 9.4.4一起使用,对查询和架构进行了修改,如下所示:

假设我有这两个表Table1Table2

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

如何在动态查询中编译此公式并将其插入目标表?


问题答案:

动态查询多列语句的基本查询-忽略该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条件以使其清楚。

以上仍然忽略了condition。首先,不要WHERE在该condition列中包含关键字。那只是噪音而已,无济于事:

INSERT INTO Table3(tbl_src, col_src, tbl_des, col_des, condition)
VALUES ('Table1','col1','Table2','col1', **'col1 >=1'**)  -- without WHERE!
     , ('Table1', ...

警告

这种方法本质上是不安全的。该condition持有表达式需要被连接起来“为是”,那么你是完全开放的 SQL注入攻击
。您需要确保不受信任的用户无法以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子句中添加通用条件。

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;

条件是AND的,并且WHERE仅在有条件的情况下才添加子句-否则,结果NULL值将吞噬表达式中添加的关键字' WHERE ' || string_agg(condition, ' AND '))

DO命令或plpgsql函数中使用此命令可以动态执行,就像我之前的答案中所指示的那样

plpgsql基本功能:

CREATE OR REPLACE FUNCTION f_test()
  RETURNS void AS
$func$
BEGIN
   EXECUTE (
   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
   );
END
$func$ LANGUAGE plpgsql;


 类似资料:
  • 问题内容: 我的Postgres版本是: “PostgreSQL 9.4.4, compiled by Visual C++ build 1800, 32-bit” 假设我有两个表Table1和Table2,分别具有columncol1和col2。 还有另一个表,Table3用于存储将数据从迁移Table1到的公式Table2: 如何在动态查询中编译此公式并将其插入目标表? 问题答案: 动态构建命

  • 问题内容: 我想在具有动态列的表中添加值。我设法用动态列创建了一个表,但无法弄清楚如何插入数据。 问题答案: 您还可以使用数据库元数据获取列名。这样的好处是,您甚至不需要知道列名,而是可以在您的代码中动态检索它们。 一旦有了列名,就可以像平常一样使用它(List.size()当然会给出列数)。 更新: 此代码假定您将正确类型的对象传递给PreparedStatement.setObject(Obj

  • 问题内容: 我已经徒劳地搜索了很长时间,不得不承认失败并寻求帮助,我正在尝试修改数据透视查询,以从具有以下数据的表中生成结果的动态查询: 为了显示这样的内容,其中页码列取决于用户访问的页面数: 我已经通过对列中的硬编码进行了管理,但是显然我不想继续更改脚本以容纳越来越多的页面。 到目前为止,我有一些类似的东西: 任何帮助或正确方向的指点将不胜感激! 提前致谢! 问题答案: 我所看到的关于动态枢轴的

  • 问题内容: 我试图找到一种方法来返回具有动态列数的记录集。我可以编写一个查询来生成需要的列名列表,如下所示: 这将返回一个简短的列表,例如’poke’,’prod’,’hit’,’drop’等。然后,我希望生成一个表,其中显示了一系列测试,其中每个测试都在其中运行。每天早晨,我们查看开发人员的工作并对其进行戳戳和刺戳,以便每天进行每次测试。我可以静态编写此查询: 但是,这是硬编码到我们每天运行的测

  • 我正在做一个自动数据库填充程序,我遇到了一个我无法理解的错误。 我正在开发一个脚本,它应该处理大量文件,包含多个值。文件中的信息具有以下结构: id time_stamp(值1值2值3值4值5)*i(值1值2值3值4值5)*n(值1值2) - I和n (n = nGrupos)是已知的,I从1变化到I,n从1变化到2。每个括号集将被插入到不同的表中,因此有以下5个值。 我遇到麻烦的代码是(我不能让

  • 问题内容: 我试图使用临时表开发此存储过程,但是那行不通,所以我改用表变量。我需要对表变量执行临时动态查询,然后使用该表变量执行最终查询。问题是我收到错误消息“必须声明标量变量@clms”。我假设Exec没有该表变量的作用域? 问题答案: 这是简单的最小示例。您可以使用语句。关键是要在动态查询的内部和外部声明表变量。在动态查询结束时,只需从表变量中选择并将结果集插入外部表变量中即可: