使用forall立即使用for for Update语句
我需要根据查询获取的数据更新表。 但是,在查询中,我使用ListAgg生成列名称及其相应的值。 我能够通过使用简单的循环使用行处理来更新表,但是我正在探索使用即时执行forall的方法,因为我正在更改更新语句运行时的设置子句。
set serveroutput on;
DECLARE
l_sql VARCHAR2(4000);
cursor c1 is SELECT
OFFER_MIGRATION_ID,
listagg(column_name||' = nvl('||column_name||','''||DEFAULT_CHAR_VALUE||''')', ','||chr(13)) within group (order by column_name) as set_clause
FROM
(
SELECT distinct och.OFFER_MIGRATION_ID,
och.ATTR_ID,
ch_map.COLUMN_NAME,
coalesce(och_list.value_name,och.DEFAULT_CHAR_VALUE) as DEFAULT_CHAR_VALUE
FROM OFFERING_CHARS och,
CHAR_MAP ch_map,
OFFERING_CHARS_list och_list
Where ch_map.transformation = 'CONSTANT_DICT'
and ch_map.attr_id = och.ATTR_ID
and och.DEFAULT_CHAR_VALUE is not null
and och_list.offer_migration_id(+) = och.offer_migration_id
and och_list.characteristic_id(+) = och.characteristic_id
and och_list.value(+) = och.DEFAULT_CHAR_VALUE
)
GROUP BY OFFER_MIGRATION_ID;
TYPE char_list IS TABLE OF c1%rowtype index by pls_integer;
l_char_list char_list;
BEGIN
/******** CONSTANT_FROM_DICT *********/
open c1;
fetch c1 bulk collect into l_char_list;
close c1;
FORALL i IN l_char_list.first .. l_char_list.last
EXECUTE IMMEDIATE 'UPDATE product_char SET :1 WHERE offer_migration_id = '||l_char_list(i).offer_migration_id
using l_char_list(i).set_clause;
COMMIT;
END;
此块给出错误 -
Error report -
ORA-06550: line 35, column 92:
PLS-00440: FORALL bulk IN-bind variables cannot be used here
ORA-06550: line 35, column 5:
PL/SQL: Statement ignored
ORA-06550: line 35, column 5:
PLS-00435: DML statement without BULK In-BIND cannot be used inside FORALL
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
光标的set_clause列的值将就像 -
OFFER_MIGRATION_ID, SET_CLAUSE
10001 "CCA_CATEGORY = nvl(CCA_CATEGORY,'PD'),CCA_LIFECYCLE_STATUS = nvl(CCA_LIFECYCLE_STATUS,'A'),EQUIPMENT_TYPE = nvl(EQUIPMENT_TYPE,'Devices')"
20001 DATA_ALLOWANCE_SO = nvl(DATA_ALLOWANCE_SO,'9225')
20023 "DURATION = nvl(DURATION,'6'),DATA_ALLOWANCE_SUP_OFFER = nvl(DATA_ALLOWANCE_SUP_OFFER,'9203')"
20024 DATA_ALLOWANCE_SUP_OFFER = nvl(DATA_ALLOWANCE_SUP_OFFER,'9203')
我的db是 -
Oracle Database 19c Standard Edition 2 Release 19.0.0.0.0 - Production
在plsql块中使用的循环,我正在寻找更好执行需要很长时间。
FOR i IN 1..l_char_list.COUNT
LOOP
l_sql := 'UPDATE stgdm_product_char SET '||chr(13)||l_char_list(i).set_clause||chr(13)||' WHERE offer_migration_id = '||l_char_list(i).offer_migration_id;
-- dbms_output.put_line(l_sql);
EXECUTE IMMEDIATE l_sql;
END LOOP;
I Require to update a table based on data fetched from a query.
however in query I am generating Column Name and its respective values using LISTAGG.
I am able to update the table using the row by row processing with simple loop however I am exploring ways to utilize the FORALL with EXECUTE IMMEDIATE since I am changing the SET clause of UPDATE statement runtime.
set serveroutput on;
DECLARE
l_sql VARCHAR2(4000);
cursor c1 is SELECT
OFFER_MIGRATION_ID,
listagg(column_name||' = nvl('||column_name||','''||DEFAULT_CHAR_VALUE||''')', ','||chr(13)) within group (order by column_name) as set_clause
FROM
(
SELECT distinct och.OFFER_MIGRATION_ID,
och.ATTR_ID,
ch_map.COLUMN_NAME,
coalesce(och_list.value_name,och.DEFAULT_CHAR_VALUE) as DEFAULT_CHAR_VALUE
FROM OFFERING_CHARS och,
CHAR_MAP ch_map,
OFFERING_CHARS_list och_list
Where ch_map.transformation = 'CONSTANT_DICT'
and ch_map.attr_id = och.ATTR_ID
and och.DEFAULT_CHAR_VALUE is not null
and och_list.offer_migration_id(+) = och.offer_migration_id
and och_list.characteristic_id(+) = och.characteristic_id
and och_list.value(+) = och.DEFAULT_CHAR_VALUE
)
GROUP BY OFFER_MIGRATION_ID;
TYPE char_list IS TABLE OF c1%rowtype index by pls_integer;
l_char_list char_list;
BEGIN
/******** CONSTANT_FROM_DICT *********/
open c1;
fetch c1 bulk collect into l_char_list;
close c1;
FORALL i IN l_char_list.first .. l_char_list.last
EXECUTE IMMEDIATE 'UPDATE product_char SET :1 WHERE offer_migration_id = '||l_char_list(i).offer_migration_id
using l_char_list(i).set_clause;
COMMIT;
END;
This block gives error --
Error report -
ORA-06550: line 35, column 92:
PLS-00440: FORALL bulk IN-bind variables cannot be used here
ORA-06550: line 35, column 5:
PL/SQL: Statement ignored
ORA-06550: line 35, column 5:
PLS-00435: DML statement without BULK In-BIND cannot be used inside FORALL
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
The values for set_clause column from the cursor will be like for example --
OFFER_MIGRATION_ID, SET_CLAUSE
10001 "CCA_CATEGORY = nvl(CCA_CATEGORY,'PD'),CCA_LIFECYCLE_STATUS = nvl(CCA_LIFECYCLE_STATUS,'A'),EQUIPMENT_TYPE = nvl(EQUIPMENT_TYPE,'Devices')"
20001 DATA_ALLOWANCE_SO = nvl(DATA_ALLOWANCE_SO,'9225')
20023 "DURATION = nvl(DURATION,'6'),DATA_ALLOWANCE_SUP_OFFER = nvl(DATA_ALLOWANCE_SUP_OFFER,'9203')"
20024 DATA_ALLOWANCE_SUP_OFFER = nvl(DATA_ALLOWANCE_SUP_OFFER,'9203')
My DB is -
Oracle Database 19c Standard Edition 2 Release 19.0.0.0.0 - Production
The loop which is working inside the PLSQL block I am looking for ways to better implement it instead of going row by row since it takes long time to execute.
FOR i IN 1..l_char_list.COUNT
LOOP
l_sql := 'UPDATE stgdm_product_char SET '||chr(13)||l_char_list(i).set_clause||chr(13)||' WHERE offer_migration_id = '||l_char_list(i).offer_migration_id;
-- dbms_output.put_line(l_sql);
EXECUTE IMMEDIATE l_sql;
END LOOP;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您不需要这么复杂。由于目标表具有已知的固定列集,因此您只能在
pivot
子句中白色列表这些列,然后使用Merge
语句(那么您只需要单个SQL语句,不需要动态SQL)。由于您尚未提供适当的最小可重复的示例,
char_map
和offering_chars_list
进入单个表your_combined_tables ,它可以简单地进行反向工程师:
然后您可以使用:
然后在之后 使用:
合并
,该表包含:db<> fiddle
You do not need it to be so complicated. Since the destination table has a known, fixed set of columns then you can just white-list those columns in a
PIVOT
clause and then use aMERGE
statement (then you only need a single SQL statement and do not need dynamic SQL).Since you have not provided a proper minimal reproducible example, I have combined all three of your input tables
OFFERING_CHARS
,CHAR_MAP
andOFFERING_CHARS_list
into a single tableyour_combined_tables
which is much simpler to reverse engineer:Then you can use:
Then after the
MERGE
, the table contains:db<>fiddle here