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_AGGREGATE
、T_B_AGGREGATE
和 T_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;
好的;我知道查询不是那么简单,但没有太大变化 - 只有 CREATE
和 FROM
中的 table 个名称(也许在其他地方,但或多或少是“它”)。任何像样的文本编辑器的 search/replace 功能都应该能够快速完成。
如果你想在一个循环中动态执行它(阅读:PL/SQL),你可以 - 但动态 SQL 不缩放,难以维护,调试起来很痛苦。因此,如果您只做一次,请考虑运行 3 个单独的语句。
动态如何实现?
您必须创建一个包含整个 DDL 语句的字符串(我们通常将它们放入本地声明的变量中)。为什么?因为您不能从 PL/SQL 否则执行 DDL。
如果涉及多个 tables and/or 列,您必须合并语句的“固定”部分(如 create table
、select
、 from
, 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 在他回答的第二部分描述了这个程序的宝贵背景。
我的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_AGGREGATE
、T_B_AGGREGATE
和 T_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;
好的;我知道查询不是那么简单,但没有太大变化 - 只有 CREATE
和 FROM
中的 table 个名称(也许在其他地方,但或多或少是“它”)。任何像样的文本编辑器的 search/replace 功能都应该能够快速完成。
如果你想在一个循环中动态执行它(阅读:PL/SQL),你可以 - 但动态 SQL 不缩放,难以维护,调试起来很痛苦。因此,如果您只做一次,请考虑运行 3 个单独的语句。
动态如何实现?
您必须创建一个包含整个 DDL 语句的字符串(我们通常将它们放入本地声明的变量中)。为什么?因为您不能从 PL/SQL 否则执行 DDL。
如果涉及多个 tables and/or 列,您必须合并语句的“固定”部分(如 create table
、select
、 from
, 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 在他回答的第二部分描述了这个程序的宝贵背景。