Oracle SQL:在“立即执行”中的内部循环中使用外部循环标识符
我必须执行32次非常类似的操作,即为给定记录(给定季度)设置行中一列的值 为了简化我的代码并使其美观,我想使用带有execute immediate的for循环,使用I_cnt动态设置语句中的列名 我正在使用Oracle 10g 当我调用该过程时,Oracle返回 SQL错误:ORA-00904:“REC”。“QUARTER_MEL”:niepoprawny IdentityFicator ORA-06512:przy“LREBIRT.P_PFPL_风险概况_测试”,linia 55 90400000-%s:无效标识符 当我调用下面的过程时,正确计算了v_risk_volume和v_risk_amount,它无法立即执行我的语句 我的程序守则:Oracle SQL:在“立即执行”中的内部循环中使用外部循环标识符,sql,for-loop,oracle10g,execute-immediate,Sql,For Loop,Oracle10g,Execute Immediate,我必须执行32次非常类似的操作,即为给定记录(给定季度)设置行中一列的值 为了简化我的代码并使其美观,我想使用带有execute immediate的for循环,使用I_cnt动态设置语句中的列名 我正在使用Oracle 10g 当我调用该过程时,Oracle返回 SQL错误:ORA-00904:“REC”。“QUARTER_MEL”:niepoprawny IdentityFicator ORA-06512:przy“LREBIRT.P_PFPL_风险概况_测试”,linia 55 90400
PROCEDURE CALCULATE_RESULT_TABLE AS
v_risk_volume float;
v_risk_amount float;
v_sql varchar2(1000);
BEGIN
for rec in (select * from PFPL_RISKPROFILE_BASIS_TEST)
LOOP
for i_cnt in 1..32
LOOP
DBMS_OUTPUT.PUT_LINE(rec.quarter_mel);
select Q_VOLUME, Q_AMOUNT into v_risk_volume, v_risk_amount from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = i_cnt;
DBMS_OUTPUT.PUT_LINE(v_risk_volume);
DBMS_OUTPUT.PUT_LINE(v_risk_amount);
v_sql := 'update PFPL_RISKPROFILE_RES_TEST t set Q_'||i_cnt||'_volume = v_risk_volume/rec.Q_VOLUME, Q_'||i_cnt||'_amount = v_risk_amount/rec.Q_AMOUNT where t.QUARTER_MEL = rec.QUARTER_MEL';
DBMS_OUTPUT.PUT_LINE(v_sql);
EXECUTE IMMEDIATE v_sql;
END LOOP;
END LOOP;
END CALCULATE_RESULT_TABLE;
PROCEDURE CALCULATE_RESULT_TABLE AS
v_risk_volume float;
v_risk_amount float;
v_i_volume varchar2(30);
v_i_amount varchar2(30);
v_sql varchar2(1000);
BEGIN
for rec in (select * from PFPL_RISKPROFILE_RES_TEST)
LOOP
DBMS_OUTPUT.PUT_LINE(rec.quarter_mel);
NULL;
for i in (select * from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter between 1 and 32 order by quarter)
LOOP
if rec.Q_volume > 0 then v_risk_volume := round(i.Q_VOLUME/rec.Q_volume,4); else v_risk_volume := 0; end if;
if rec.Q_amount > 0 then v_risk_amount := round(i.Q_AMOUNT/rec.Q_amount,4); else v_risk_amount := 0; end if;
v_i_volume := 'Q_'||i.quarter||'_volume';
v_i_amount := 'Q_'||i.quarter||'_amount';
v_sql := 'update PFPL_RISKPROFILE_RES_TEST t set '||v_i_volume||' = :v, '||v_i_amount||' = :a where t.QUARTER_MEL = :q';
EXECUTE IMMEDIATE v_sql USING v_risk_volume, v_risk_amount, rec.quarter_mel;
END LOOP;
END LOOP;
END CALCULATE_RESULT_TABLE;
dbms_输出的结果:
1-2012
7.
448787,05
更新PFPL_RISKPROFILE_RES_TEST t set Q_1_volume=v_risk_volume/rec.Q_volume,Q_1_amount=v_risk_amount/rec.Q_amount,其中t.QUARTER_MEL=rec.QUARTER_MEL
先前更正后程序的当前版本:
PROCEDURE CALCULATE_RESULT_TABLE AS
v_risk_volume float;
v_risk_amount float;
v_sql varchar2(1000);
BEGIN
for rec in (select * from PFPL_RISKPROFILE_BASIS_TEST)
LOOP
DBMS_OUTPUT.PUT_LINE(rec.quarter_mel);
for i_cnt in 1..32
LOOP
DBMS_OUTPUT.PUT_LINE(i_cnt);
DBMS_OUTPUT.PUT_LINE(rec.quarter_mel);
select Q_VOLUME, Q_AMOUNT into v_risk_volume, v_risk_amount from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = i_cnt;
if rec.Q_volume > 0 then v_risk_volume := round(v_risk_volume/rec.Q_volume,4); else v_risk_volume := 0; end if;
if rec.Q_amount > 0 then v_risk_amount := round(v_risk_amount/rec.Q_amount,4); else v_risk_amount := 0; end if;
v_sql := 'update PFPL_RISKPROFILE_RES_TEST t set Q_'||i_cnt||'_volume = :v, Q_'||i_cnt||'_amount = :a where t.QUARTER_MEL = :q';
DBMS_OUTPUT.PUT_LINE(v_sql);
EXECUTE IMMEDIATE v_sql USING v_risk_volume, v_risk_amount, rec.quarter_mel;
END LOOP;
END LOOP;
END CALCULATE_RESULT_TABLE;
您好,我尝试了杰夫的建议,但我仍然有一个问题,这真的很难看,我几乎哭了写代码-我做了10个季度,我仍然需要粘贴丢失的22个季度。现在,这个过程处理了四行循环中的两行
PROCEDURE CALCULATE_RESULT_TABLE AS
v_risk_volume_1 FLOAT;
v_risk_volume_2 FLOAT;
v_risk_volume_3 FLOAT;
v_risk_volume_4 FLOAT;
v_risk_volume_5 FLOAT;
v_risk_volume_6 FLOAT;
v_risk_volume_7 FLOAT;
v_risk_volume_8 FLOAT;
v_risk_volume_9 FLOAT;
v_risk_volume_10 FLOAT;
v_risk_amount_1 FLOAT;
v_risk_amount_2 FLOAT;
v_risk_amount_3 FLOAT;
v_risk_amount_4 FLOAT;
v_risk_amount_5 FLOAT;
v_risk_amount_6 FLOAT;
v_risk_amount_7 FLOAT;
v_risk_amount_8 FLOAT;
v_risk_amount_9 FLOAT;
v_risk_amount_10 FLOAT;
BEGIN
for rec in (select * from PFPL_RISKPROFILE_BASIS_TEST order by quarter_mel)
LOOP
DBMS_OUTPUT.PUT_LINE(rec.quarter_mel);
select Q_VOLUME, Q_AMOUNT into v_risk_volume_1, v_risk_amount_1 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 1;
if rec.Q_volume > 0 then v_risk_volume_1 := round(v_risk_volume_1/rec.Q_volume,4); else v_risk_volume_1 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_1 := round(v_risk_amount_1/rec.Q_amount,4); else v_risk_amount_1 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_2, v_risk_amount_2 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 2;
if rec.Q_volume > 0 then v_risk_volume_2 := round(v_risk_volume_2/rec.Q_volume,4); else v_risk_volume_2 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_2 := round(v_risk_amount_2/rec.Q_amount,4); else v_risk_amount_2 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_3, v_risk_amount_3 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 3;
if rec.Q_volume > 0 then v_risk_volume_3 := round(v_risk_volume_3/rec.Q_volume,4); else v_risk_volume_3 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_3 := round(v_risk_amount_3/rec.Q_amount,4); else v_risk_amount_3 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_4, v_risk_amount_4 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 4;
if rec.Q_volume > 0 then v_risk_volume_4 := round(v_risk_volume_4/rec.Q_volume,4); else v_risk_volume_4 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_4 := round(v_risk_amount_4/rec.Q_amount,4); else v_risk_amount_4 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_5, v_risk_amount_5 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 5;
if rec.Q_volume > 0 then v_risk_volume_5 := round(v_risk_volume_5/rec.Q_volume,4); else v_risk_volume_5 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_5 := round(v_risk_amount_5/rec.Q_amount,4); else v_risk_amount_5 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_6, v_risk_amount_6 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 6;
if rec.Q_volume > 0 then v_risk_volume_6 := round(v_risk_volume_6/rec.Q_volume,4); else v_risk_volume_6 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_6 := round(v_risk_amount_6/rec.Q_amount,4); else v_risk_amount_6 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_7, v_risk_amount_7 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 7;
if rec.Q_volume > 0 then v_risk_volume_7 := round(v_risk_volume_7/rec.Q_volume,4); else v_risk_volume_7 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_7 := round(v_risk_amount_7/rec.Q_amount,4); else v_risk_amount_7 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_8, v_risk_amount_8 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 8;
if rec.Q_volume > 0 then v_risk_volume_8 := round(v_risk_volume_8/rec.Q_volume,4); else v_risk_volume_8 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_8 := round(v_risk_amount_8/rec.Q_amount,4); else v_risk_amount_8 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_9, v_risk_amount_9 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 9;
if rec.Q_volume > 0 then v_risk_volume_9 := round(v_risk_volume_9/rec.Q_volume,4); else v_risk_volume_9 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_9 := round(v_risk_amount_9/rec.Q_amount,4); else v_risk_amount_9 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_10, v_risk_amount_10 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 10;
if rec.Q_volume > 0 then v_risk_volume_10 := round(v_risk_volume_10/rec.Q_volume,4); else v_risk_volume_10 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_10 := round(v_risk_amount_10/rec.Q_amount,4); else v_risk_amount_10 := 0; end if;
update PFPL_RISKPROFILE_RES_TEST set
Q_1_volume = v_risk_volume_1,
Q_2_volume = v_risk_volume_2,
Q_3_volume = v_risk_volume_3,
Q_4_volume = v_risk_volume_4,
Q_5_volume = v_risk_volume_5,
Q_6_volume = v_risk_volume_6,
Q_7_volume = v_risk_volume_7,
Q_8_volume = v_risk_volume_8,
Q_9_volume = v_risk_volume_9,
Q_10_volume = v_risk_volume_10 where quarter_mel = rec.quarter_mel;
update PFPL_RISKPROFILE_RES_TEST set
Q_1_amount = v_risk_amount_1,
Q_2_amount = v_risk_amount_2,
Q_3_amount = v_risk_amount_3,
Q_4_amount = v_risk_amount_4,
Q_5_amount = v_risk_amount_5,
Q_6_amount = v_risk_amount_6,
Q_7_amount = v_risk_amount_7,
Q_8_amount = v_risk_amount_8,
Q_9_amount = v_risk_amount_9,
Q_10_amount = v_risk_amount_10 where quarter_mel = rec.quarter_mel;
END LOOP;
END CALCULATE_RESULT_TABLE;
v_sql:=“更新PFPL_RISKPROFILE_Resu TEST t set Q| | | | i_cnt | | | i| | | | | | | | | | | | | | | | i| | | | | | | | | | | U金额=v|
您没有在此处传递变量值。您需要在EXECUTE IMMEDIATE中使用bind变量和USING子句来引用bind值
您需要按照以下方式进行操作:
v_sql := 'update PFPL_RISKPROFILE_RES_TEST t set Q_'||i_cnt||'_volume = :v_risk_volume/rec.Q_VOLUME, Q_'||i_cnt||'_amount = :v_risk_amount/:rec.Q_AMOUNT where t.QUARTER_MEL = rec.QUARTER_MEL';
execute immediate v_sql using v_risk_volume, v_risk_amount, rec.Q_AMOUNT
所以,我终于找到了最后一个错误的原因,我想在这里编译答案的不同元素 第一个错误是使用executeimmediate,执行的sql不应该包含任何引用,我用bind变量替换了它,这样就可以了 第二个错误是,当内部光标从1..32移动时,在所有32次迭代中,不一定要选择v_risk_volume和v_risk_amount中的值,并且该过程在第一次迭代时崩溃,其中选择。。。进入什么也没回来 因此,我改变了逻辑,将内部光标放在select中的表上。。。进入语句,现在它运行得非常完美。我对这个解决方案很满意,它只需要最少的代码就可以完成任务,而且处理的最大记录数大约为1024条,因此性能完全可以接受 本程序的最终代码为:
PROCEDURE CALCULATE_RESULT_TABLE AS
v_risk_volume float;
v_risk_amount float;
v_sql varchar2(1000);
BEGIN
for rec in (select * from PFPL_RISKPROFILE_BASIS_TEST)
LOOP
for i_cnt in 1..32
LOOP
DBMS_OUTPUT.PUT_LINE(rec.quarter_mel);
select Q_VOLUME, Q_AMOUNT into v_risk_volume, v_risk_amount from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = i_cnt;
DBMS_OUTPUT.PUT_LINE(v_risk_volume);
DBMS_OUTPUT.PUT_LINE(v_risk_amount);
v_sql := 'update PFPL_RISKPROFILE_RES_TEST t set Q_'||i_cnt||'_volume = v_risk_volume/rec.Q_VOLUME, Q_'||i_cnt||'_amount = v_risk_amount/rec.Q_AMOUNT where t.QUARTER_MEL = rec.QUARTER_MEL';
DBMS_OUTPUT.PUT_LINE(v_sql);
EXECUTE IMMEDIATE v_sql;
END LOOP;
END LOOP;
END CALCULATE_RESULT_TABLE;
PROCEDURE CALCULATE_RESULT_TABLE AS
v_risk_volume float;
v_risk_amount float;
v_i_volume varchar2(30);
v_i_amount varchar2(30);
v_sql varchar2(1000);
BEGIN
for rec in (select * from PFPL_RISKPROFILE_RES_TEST)
LOOP
DBMS_OUTPUT.PUT_LINE(rec.quarter_mel);
NULL;
for i in (select * from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter between 1 and 32 order by quarter)
LOOP
if rec.Q_volume > 0 then v_risk_volume := round(i.Q_VOLUME/rec.Q_volume,4); else v_risk_volume := 0; end if;
if rec.Q_amount > 0 then v_risk_amount := round(i.Q_AMOUNT/rec.Q_amount,4); else v_risk_amount := 0; end if;
v_i_volume := 'Q_'||i.quarter||'_volume';
v_i_amount := 'Q_'||i.quarter||'_amount';
v_sql := 'update PFPL_RISKPROFILE_RES_TEST t set '||v_i_volume||' = :v, '||v_i_amount||' = :a where t.QUARTER_MEL = :q';
EXECUTE IMMEDIATE v_sql USING v_risk_volume, v_risk_amount, rec.quarter_mel;
END LOOP;
END LOOP;
END CALCULATE_RESULT_TABLE;
v_sql语句似乎不能包含
rec.Q.
字符串。当我连接它们时,错误消失了。但是我还不在家,现在v_risk_volume/rec.Q_volume分区返回一个十进制值,例如解释为,0056
,逗号打断了语句。可能是由于我的区域设置……我通过在v_sql语句中使用:variable
解决了这个问题,然后使用variable执行立即v_sql代码>。你在我发布解决方案的同时发现了。您可以将其标记为已回答。好吧,我让它工作了,但我不明白一点:在外循环中,我有几个记录,我想循环外循环中的每个记录,并且对于每个记录,执行内循环(因此对于32个I_cnt中的每个,执行v_sql语句)。但当我调用该过程时,它只对外部循环的一条记录执行并退出。有什么想法吗?一个更好的解决方案可能是完全避免循环和动态sql,并在一个UPDATE语句中完成这一切,因为您只更新一个表。rec.Q*
引用也需要是绑定变量。是的,我自己继续调整,发现了这一点。谢谢然而,我仍然有一个问题,即在对外部循环的一条记录执行内部循环后,过程结束,而不对外部循环的其他记录执行内部循环,有什么线索吗?@StephaneDubois外部循环依赖于rec in的(从PFPL\u RISKPROFILE\u BASIS\u TEST中选择*)
。select实际返回多少行?select此时返回4行。当我注释代码外的内部循环时,外部循环正确地运行在4行中。但是,当执行内部循环时,它会在处理select的第一行之后立即退出。您是否可以注释掉EXECUTE IMMEDIATE并检查一次。