I have to execute 32 times a very similar operation, that is setting the value of a column in a row for a given record (for a given quarter).
To simplify my code and thrive for beauty, I wanted to use a for loop with an execute immediate, using I_cnt to dynamically set the column name in the statement.
I am using Oracle 10g.
When I call the procedure, Oracle returns
SQL Error: ORA-00904: "REC"."QUARTER_MEL": niepoprawny identyfikator ORA-06512: przy "LREBIRT.P_PFPL_RISKPROFILE_TEST", linia 55 00904. 00000 - "%s: invalid identifier"
When I call the procedure below, v_risk_volume and v_risk_amount are correctly calculated, it fails to execute immediate my statement.
The code of my procedure:
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;
The result of the dbms_output:
1-2012 7 448787,05 update PFPL_RISKPROFILE_RES_TEST t set Q_1_volume = v_risk_volume/rec.Q_VOLUME, Q_1_amount = v_risk_amount/rec.Q_AMOUNT where t.QUARTER_MEL = rec.QUARTER_MEL
Current version of the procedure after previous corrections:
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;
Hello again, I tried what Jeff proposed, but I still have a problem, and it's really ugly, I almost cried writing the code - I did it for 10 quarters, I still need to paste the missing 22 quarters. Now the procedure treated two of the four rows of the loop.
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;