Oracle PL/SQL - 循环值作为没有动态 SQL 的动态列名
Posted
技术标签:
【中文标题】Oracle PL/SQL - 循环值作为没有动态 SQL 的动态列名【英文标题】:Oracle PL/SQL - Loop value as dynamic column name without dynamic SQL 【发布时间】:2020-11-25 17:33:04 【问题描述】:我想用相同的值更新具有相同列名的多个表,而不是对每个表进行更新,并且由于 Oracle 不提供一次更新多个表的方法,我虽然使用为此循环。
我试过了,但它没有按预期工作:
begin
for i in (select column_value from table(sys.dbms_debug_vc2coll('tab1', 'tab2'))) loop
update i set my_col = 'my value';
end loop;
end;
我知道我可以通过 execute immediate
使用动态 SQL,但有没有办法避免它?
【问题讨论】:
简单回答:否。 这看起来很奇怪,为什么要在多个表中为所有行存储相同的值?似乎这是解决您真正遇到的任何问题的错误方法。 @AndrewSayer 这不是针对所有行,我提供的示例代码是高度简化的。在实际情况中,有一个where
子句说明要更新哪一行。
好的,你可以使用你的 SQL 来生成 SQL,你不必使用 execute immediate 或 dbms_sql 来运行它——你只需要: spool 一个脚本,用眼睛检查它,运行它手动。这是您所追求的还是您实际上希望它自己执行(在这种情况下您必须使用动态 SQL)。
@user5507535 避免过多的动态 SQL 很好,但同时避免会导致其他问题。学习一些我在回答 here 中解释过的处理动态 SQL 的技巧可能会有所帮助。
【参考方案1】:
问题(以及问题)看起来很简单:
用相同的值更新具有相同列名的多个表
如何根据这些表和一个instead of
触发器创建一个视图来完成这项工作?方法如下:
示例表:
SQL> select * from tab_a;
ID M
---------- -
1 x
2 y
SQL> select * from tab_b;
NA MY_
-- ---
LF www
JW zzz
MC
查看:
SQL> create or replace view v_tabs as
2 select to_char(id) idn, my_col from tab_a
3 union all
4 select name , my_col from tab_b;
View created.
SQL> select * from v_tabs;
IDN MY_
---------------------------------------- ---
1 x
2 y
LF www
JW zzz
MC
而不是触发器:
SQL> create or replace trigger trg_tabs
2 instead of update on v_tabs
3 for each row
4 begin
5 update tab_a set my_col = :new.my_col;
6 update tab_b set my_col = :new.my_col;
7 end;
8 /
Trigger created.
测试:
SQL> update v_tabs set my_col = 'e';
5 rows updated.
SQL> select * from tab_a;
ID M
---------- -
1 e
2 e
SQL> select * from tab_b;
NA MY_
-- ---
LF e
JW e
MC e
SQL>
所有涉及的表中的所有MY_COL
值都设置为e
。这就是你要求的,对吧?
【讨论】:
【参考方案2】:如果您不能使用execute immediate
,请尝试使用DBMS_SQL
包:
https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_sql.htm#i996963
这是一个从文档中获取的关于如何使用这个包的语法示例:
CREATE OR REPLACE PROCEDURE demo(salary IN NUMBER) AS
cursor_name INTEGER;
rows_processed INTEGER;
BEGIN
cursor_name := dbms_sql.open_cursor;
DBMS_SQL.PARSE(cursor_name, 'DELETE FROM emp WHERE sal > :x', DBMS_SQL.NATIVE);
DBMS_SQL.BIND_VARIABLE(cursor_name, ':x', salary);
rows_processed := DBMS_SQL.EXECUTE(cursor_name);
DBMS_SQL.CLOSE_CURSOR(cursor_name);
EXCEPTION
WHEN OTHERS THEN
DBMS_SQL.CLOSE_CURSOR(cursor_name);
END;
/
【讨论】:
以上是关于Oracle PL/SQL - 循环值作为没有动态 SQL 的动态列名的主要内容,如果未能解决你的问题,请参考以下文章
PL/SQL Oracle :- 在传递值时动态 UNPIVOT ORACLE TABLE