Oracle SQL 中的 FOR 循环或将 SQL 应用于多个 Oracle 表

FOR loop in Oracle SQL or Apply SQL to multiple Oracle tables

我的SQL有点生疏,所以我不知道下面是否可行:

我有多个 tables t_a, t_b, t_c 具有相同的列布局,我想对它们应用相同的操作,即输出一些聚合成另一个table。对于 table t_x 这看起来像这样:

CREATE TABLE t_x_aggregate (
    <here the col definitions which are the same for all new tables t_[abc]_aggregate>
);

INSERT INTO t_x_aggregate(id, ...)
SELECT id, SUM(factor*amount)
FROM t_x
WHERE some fixed condition
GROUP BY id;

我现在想围绕这个执行类似 FOR 循环的操作:

for t_x in t_a, t_b, t_c
    CREATE TABLE ...
    INSERT INTO ...
end for

这在 SQL 中可行吗?或者我需要为此构建另一种语言的包装器吗?

那么,该操作的结果将是 3 个新的 tables? T_A_AGGREGATET_B_AGGREGATET_C_AGGREGATE?

我认为最快的方法是编写 3 个单独的 CREATE TABLE 语句,例如

create table t_a_aggregate as
  select id, sum(factor * amount) suma
  from t_a
  where some_condition
  group by id;

create table t_b_aggregate as
  select id, sum(factor * amount) suma
  from t_b
  where some_condition
  group by id;

create table t_c_aggregate as
  select id, sum(factor * amount) suma
  from t_c
  where some_condition
  group by id;

好的;我知道查询不是那么简单,但没有太大变化 - 只有 CREATEFROM 中的 table 个名称(也许在其他地方,但或多或​​少是“它”)。任何像样的文本编辑器的 search/replace 功能都应该能够快速完成。

如果你想在一个循环中动态执行它(阅读:PL/SQL),你可以 - 但动态 SQL 不缩放,难以维护,调试起来很痛苦。因此,如果您只做一次,请考虑运行 3 个单独的语句。


动态如何实现?

您必须创建一个包含整个 DDL 语句的字符串(我们通常将它们放入本地声明的变量中)。为什么?因为您不能从 PL/SQL 否则执行 DDL。

如果涉及多个 tables and/or 列,您必须合并语句的“固定”部分(如 create tableselectfrom, order by) 与“动态”部分连接 - 例如列名。请注意,您必须在两者之间连接逗号作为分隔符。注意多个单引号的使用,因为你必须 转义 它们(或使用 q-quoting 机制)。

此外,对于多列,您可能必须在循环中执行此操作,将每个新列连接到先前组成的字符串。

它(存储在变量中的语句)由EXECUTE IMMEDIATE执行。如果写对了,就会成功。否则,它会失败,但它不会告诉你为什么它失败了(这就是为什么我说调试困难")。

所以,我们通常 显示 那个字符串(使用 dbms_output.put_line),而不是执行它,这样我们就可以看到它的样子 - 使用 copy/paste - 尝试执行它。

基本上,它可能非常复杂,而且 - 正如我所说 - 难以维护和调试。

对于 FOR 循环,您需要像这样使用 PL/SQL:(*)

declare
  type array_t is table of varchar2(10);
  array array_t := array_t('a', 'b', 'c'); 
  lo_stmt varchar2(2000);
begin
  lo_stmt :=
  'CREATE TABLE t_'||array(i)||'_aggregate ('||
  '    <here the col definitions which are the same for all new tables t_[abc]_aggregate>'||
  ');'||
  ''||
  'INSERT INTO t_'||array(i)||'_aggregate(id, ...)'||
  'SELECT id, SUM(factor*amount)'||
  'FROM t_'||array(i)||
  'WHERE some fixed condition'||
  'GROUP BY id;'||   
  execute immediate lo_stmt;
  end loop;
end;
/

另请参阅这个 SO 问题:

(*) @Littlefoot 在他回答的第二部分描述了这个程序的宝贵背景。