Procedure takes several hours to complete - sql

I'm trying to generate a report that give me the percentage of each grade for each letter for each term for each subject. The final report has subject codes like MAT, ENC, etc. as the row headers and then the terms and letter grades as the column headers. I'm currently looping through each subject, then each term, then each grade and it takes 2+ hours to complete. What is the correct/more efficient way of accomplishing this. Feel free to ask if you have any questions. Thanks for your help!!
v_subj varchar2(5);
v_grade varchar2(5);
v_termloop varchar2(6);
c_total number;
c_dfw number;
c_gradetotal number;
c_gradedfw number;
v_output varchar2(1000);
Cursor Get_Terms is
select distinct ssbsect_term_code from ssbsect
where ssbsect_term_code >= 201230
and ssbsect_term_code not like '%5'
order by 1;
Cursor Get_Subj is
Select distinct ssbsect_subj_code from ssbsect
where ssbsect_term_code >= 201230
and ssbsect_insm_code = 'DL'
and ssbsect_term_code not like '%5'
order by 1;
Cursor Get_Grade is
select distinct msvcrse_grde_code from msvcrse
where msvcrse_grde_code in ('A','B','C','D','F','S','U','W')
order by 1;
Cursor Get_Total is
select count(msvcrse_pidm) from msvcrse
join ssbsect on msvcrse_crn = ssbsect_crn
and msvcrse_Term_code = ssbsect_term_code
where msvcrse_term_code = v_termloop
and ssbsect_insm_code = 'DL'
and msvcrse_crse_numb < '3000'
and msvcrse_subj_code = v_subj
and msvcrse_gmod_code <> 'D';
Cursor Get_GradeTotal is
select count(msvcrse_pidm) from msvcrse
join ssbsect on msvcrse_crn = ssbsect_crn
and msvcrse_Term_code = ssbsect_term_code
where msvcrse_term_code = v_termloop
and ssbsect_insm_code = 'DL'
and msvcrse_grde_code like '%'||v_grade||'%'
and msvcrse_crse_numb < '3000'
and msvcrse_subj_code = v_subj
and msvcrse_gmod_code <> 'D';
Begin
Open Get_Subj;
Loop
Fetch Get_Subj into v_subj;
Exit when Get_Subj%NOTFOUND;
v_output := '';
v_output := v_subj;
Open Get_Terms;
Loop
Fetch Get_Terms into v_termloop;
Exit when Get_Terms%NOTFOUND;
Open Get_Grade;
Loop
Fetch Get_Grade into v_grade;
Exit when Get_grade%NOTFOUND;
Open Get_Total;
Fetch Get_Total into c_total;
Close Get_Total;
Open Get_GradeTotal;
Fetch Get_GradeTotal into c_gradetotal;
Close Get_GradeTotal;
if c_total = 0 then
c_total := NULL;
end if;
v_output := v_output ||'|'||nvl(100*(round(c_gradetotal/c_total,3)),0);
--dbms_output.put_line(v_subj||'|'||v_termloop||'|'||v_insm||'|'||nvl(100*(round(c_dfw/c_total,3)),0));
End Loop;
Close Get_Grade;
End Loop;
Close Get_Terms;
dbms_output.put_line(v_output);

I change a little bit your code, but the result should be the same.
Please merge the cursors get_grade and get_gradetotal, makes no sense have two in this code.
DECLARE
c_total NUMBER;
v_output VARCHAR2 ( 1000 );
CURSOR get_subj IS
SELECT DISTINCT ssbsect_subj_code
FROM ssbsect
WHERE ssbsect_term_code >= 201230
AND ssbsect_insm_code = 'DL'
AND ssbsect_term_code NOT LIKE '%5'
ORDER BY 1;
CURSOR get_terms IS
SELECT DISTINCT ssbsect_term_code
FROM ssbsect
WHERE ssbsect_term_code >= 201230
AND ssbsect_term_code NOT LIKE '%5'
ORDER BY 1;
CURSOR get_total ( lci_termloop IN ssbsect.msvcrse_term_code%TYPE
, lci_subj IN msvcrse.msvcrse_subj_code%TYPE ) IS
SELECT COUNT ( msvcrse_pidm )
FROM msvcrse
JOIN ssbsect
ON msvcrse_crn = ssbsect_crn
AND msvcrse_term_code = ssbsect_term_code
WHERE msvcrse_term_code = lci_termloop
AND ssbsect_insm_code = 'DL'
AND msvcrse_crse_numb < '3000'
AND msvcrse_subj_code = lci_subj
AND msvcrse_gmod_code <> 'D';
CURSOR get_grade IS
SELECT DISTINCT msvcrse_grde_code
FROM msvcrse
WHERE msvcrse_grde_code IN ('A', 'B', 'C', 'D', 'F', 'S', 'U', 'W')
ORDER BY 1;
CURSOR get_gradetotal ( lci_termloop IN ssbsect.msvcrse_term_code%TYPE
, lci_grade IN msvcrse.msvcrse_grde_code%TYPE
, lci_subj IN msvcrse.msvcrse_subj_code%TYPE ) IS
SELECT COUNT ( msvcrse_pidm ) AS msvcrse_pidm
FROM msvcrse
JOIN ssbsect
ON msvcrse_crn = ssbsect_crn
AND msvcrse_term_code = ssbsect_term_code
WHERE msvcrse_term_code = lci_termloop
AND ssbsect_insm_code = 'DL'
AND msvcrse_grde_code LIKE '%' || lci_grade || '%'
AND msvcrse_crse_numb < '3000'
AND msvcrse_subj_code = lci_subj
AND msvcrse_gmod_code <> 'D';
BEGIN
FOR rec_subj IN get_subj LOOP
v_output := rec_subj.ssbsect_subj_code;
FOR rec_term IN get_terms LOOP
OPEN get_total ( lci_termloop => rec_term.ssbsect_term_code
, lci_subj => rec_subj.ssbsect_subj_code );
FETCH get_total INTO c_total;
CLOSE get_total;
FOR rec_grade IN get_grade LOOP
<<grade_total>>
FOR rec_gradetotal IN get_gradetotal ( lci_termloop => rec_term.ssbsect_term_code
, lci_grade => rec_grade.msvcrse_grde_code
, lci_subj => v_output ) LOOP
IF c_total = 0 THEN
c_total := NULL;
v_output := v_output || '|';
CONTINUE grade_total; -- <-- AVOID WORK
END IF;
v_output := v_output || '|' || NVL ( 100 * ( ROUND ( rec_gradetotal.msvcrse_pidm / c_total, 3 ) ), 0 ); -- <-- PLEASE MAKE THIS CODE BETTER
--dbms_output.put_line(rec_subj.ssbsect_subj_code||'|'||rec_term.ssbsect_term_code||'|'||v_insm||'|'||nvl(100*(round(c_dfw/c_total,3)),0));
END LOOP grade_total;
END LOOP;
END LOOP;
--DBMS_OUTPUT.put_line ( rec_subj.ssbsect_subj_code );
END LOOP;
END;
I change all code without compile, please make sure the types used int the cursor.
I guess 50% of improvement, but you need test.
Let me know whether you have any question and please use table alias in SQL and be careful with loops.
Thank you.

Related

E-mail Formatting Oracle

I need some help with this procedure. I need to include in a single e-mail the whole result of the select on the first Cursor (C1).
The way the procedure is working now, it sends an e-mail for each row found. The result is, if the cursor finds 100 rows, 100 e-mails will be sent, and I don't want that to happen, I need the 100 rows in a single e-mail, following the "V_MENSAGEM" structure.
create or replace PROCEDURE PR_ENVIA_EMAIL_LOTE_ESTOQUE IS
V_REMETENTE VARCHAR2(50) := 'servidor#oracle.com.br';
V_SAUDACAO VARCHAR2(50);
V_ASSUNTO VARCHAR2(200);
V_ASSINATURA VARCHAR2(100);
V_MENSAGEM VARCHAR2(6000);
V_COD_ERRO NUMBER(2);
V_MSG_ERRO VARCHAR2(1);
TDESCRI_ARMAZEM VARCHAR2(50);
TDESCRI VARCHAR2(60);
BEGIN
FOR C1 IN (SELECT TBLOTE.NNOTFIS NOTA_FISCAL,
TBLOTE.CLOTE LOTE,
TBARMAZ.TDESCRI ARMAZEM,
TBNOTF.DDTFATU DATA_FAT_NF,
TBLOTE.DRECEBTO DATA_RECEBTO,
TBLOTE.CPRODUT COD_PRODUTO,
TBPRODU.TDESCRI PRODUTO,
TBLOTAR.QQTESTQ QTD_ESTOQUE,
Decode(TBLOTE.F_ARMAZENAGEM, 'S', 'SIM', 'N', 'NÃO') ARMAZENAGEM,
Decode(TBLOTE.SLTENCR, 'S', 'SIM', 'N', 'NÃO') ENCERRADO,
TO_DATE(Sysdate, 'dd/mm/yyyy') - TO_DATE(TBLOTE.DRECEBTO, 'dd/mm/yyyy')DIAS_EM_ESTOQUE
FROM TBLOTE,
TBLOTAR,
TBPRODU,
TBARMAZ,
TBNOTF
WHERE TBLOTE.CPRODUT = TBPRODU.CPRODUT
AND TBLOTE.CLOTE = TBLOTAR.CLOTE
AND TBLOTAR.CARMAZE = TBARMAZ.CARMAZE
AND TBLOTE.NNOTFIS = TBNOTF.NNOTFIS
AND TBLOTE.CEMPRES = TBNOTF.CEMPRES
AND TBLOTE.SLTENCR = 'N'
AND TBLOTE.F_ARMAZENAGEM = 'S'
AND TBLOTE.NNOTFIS IS NOT NULL
AND TO_DATE(Sysdate, 'dd/mm/yyyy') - TO_DATE(TBLOTE.DRECEBTO, 'dd/mm/yyyy') >= 165
ORDER BY DIAS_EM_ESTOQUE DESC)
LOOP
DBMS_OUTPUT.PUT_LINE('LENDO '||C1.NOTA_FISCAL|| ' - ' ||C1.LOTE|| ' - ' ||C1.ARMAZEM|| ' - ' ||C1.PRODUTO|| ' - Dias em Estoque: ' || C1.DIAS_EM_ESTOQUE);
BEGIN
IF TO_NUMBER(TO_CHAR(SYSDATE,'HH24')) < 12 THEN
V_SAUDACAO:= 'Bom Dia!';
ELSIF TO_NUMBER(TO_CHAR(SYSDATE,'HH24')) >= 12 AND
TO_NUMBER(TO_CHAR(SYSDATE,'HH24')) < 18 THEN
V_SAUDACAO:= 'Boa tarde!';
ELSE
V_SAUDACAO:= 'Boa noite!';
END IF;
V_ASSUNTO := 'AVISO: Lotes em estoque.';
V_MENSAGEM := ' Os seguintes lotes ja estao há pelo menos 165 dias em nosso estoque, favor verificar: '||CHR(10)||CHR(10);
V_MENSAGEM := V_MENSAGEM ||'Nota Fiscal : '||C1.NOTA_FISCAL||CHR(10)||
'Lote : '||C1.LOTE||CHR(10)||
'Armazem : '||C1.ARMAZEM||CHR(10)||
'Dt. Faturamento : '||To_Date(C1.DATA_FAT_NF, 'DD/MM/YYYY')||CHR(10)||
'Dt. Recebimento : '||C1.DATA_RECEBTO||CHR(10)||
'Produto : '||C1.PRODUTO||CHR(10)||CHR(10)||
'Qtd. em Estoque : '||C1.QTD_ESTOQUE||CHR(10)||
'Dias em Estoque : '||C1.DIAS_EM_ESTOQUE||CHR(10)||CHR(10)||
'Estamos a disposiçao.'||CHR(10)||CHR(10)||CHR(10)||
'Att. '||CHR(10)||CHR(10)||
'Departamento de T.I'||CHR(10)||
'---';
V_MENSAGEM := V_SAUDACAO||CHR(10)||CHR(10)||
V_MENSAGEM||
CHR(10)||CHR(10)||CHR(10)||CHR(10)||
V_ASSINATURA;
FOR C2 IN (SELECT EMAIL_USUARIO
FROM TBEMAIL_INTERNO
WHERE F_LOTE_ESTOQUE = 'S'
AND F_EXCLUSAO_LOGICA = 'N')
LOOP
PR_ENVIA_EMAIL(V_REMETENTE,
C2.EMAIL_USUARIO,
V_ASSUNTO,
V_MENSAGEM,
V_COD_ERRO,
V_MSG_ERRO);
END LOOP;
END;
END LOOP ;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('ATENÇÃO: ERRO AO CHAMAR ROTINA PR_ENVIA_EMAIL_LOTE_ESTOQUE: '||SQLERRM);
END PR_ENVIA_EMAIL_LOTE_ESTOQUE;
The reason you're sending the email for every iteration of the loop through cursor C1 is that the loop through C2 (the one that sends the email) is inside the loop through C1. This change should fix your issue:
...
V_MENSAGEM := V_SAUDACAO||CHR(10)||CHR(10)||
V_MENSAGEM||
CHR(10)||CHR(10)||CHR(10)||CHR(10)||
V_ASSINATURA;
END;
END LOOP ;
FOR C2 IN (SELECT EMAIL_USUARIO
FROM TBEMAIL_INTERNO
WHERE F_LOTE_ESTOQUE = 'S'
AND F_EXCLUSAO_LOGICA = 'N')
LOOP
PR_ENVIA_EMAIL(V_REMETENTE,
C2.EMAIL_USUARIO,
V_ASSUNTO,
V_MENSAGEM,
V_COD_ERRO,
V_MSG_ERRO);
END LOOP;
EXCEPTION
...

How to write "in" claus in select query when ever in_put param has some values..?

whenever users pass a list of values then we need to pause "in" condition.
the jin_son_doc will be like this "India,American Samoa"
create or replace PROCEDURE test_attendee (
out_chr_err_code OUT VARCHAR2,
out_chr_err_msg OUT VARCHAR2,
out_attendee_tab OUT return_attendee_arr_result,
in_json_doc IN VARCHAR2
) IS
l_chr_srcstage VARCHAR2(200);
l_chr_biqtab VARCHAR2(200);
l_chr_srctab VARCHAR2(200);
l_chr_bistagtab VARCHAR2(200);
l_chr_err_code VARCHAR2(255);
l_chr_err_msg VARCHAR2(255);
l_out_chr_errbuf VARCHAR2(2000);
lrec return_attendee_report;
l_num_counter NUMBER := 0;
json_doc CHAR_ARRAY(1000) := in_json_doc;
CURSOR cur_attendee_data IS
SELECT
*
FROM
(
SELECT
a.*,
ROWNUM rn
FROM
(SELECT * FROM (
SELECT
r.id request_id,
c.designation ext_att_title,
DECODE(c.attendee_type, 'externalattendees', 'External', 'Internal') attendee_type
FROM
bi_request r
LEFT JOIN bi_request_activity_day a ON a.request_id = r.id
LEFT JOIN bi_request_catering_activity b ON b.request_activity_day_id = a.id
LEFT JOIN bi_request_attendees c ON c.request_id = r.id
LEFT JOIN bi_request_act_day_room d ON d.request_activity_day_id = a.id
AND d.room = b.room
WHERE
r.state = 'CONFIRMED'
AND a.event_date BETWEEN l_start_date AND l_end_date
AND r.location_id = (
SELECT UNIQUE
( id )
FROM
bi_location
WHERE
unique_id = l_location_id
)
AND d.room_type = 'MAIN_ROOM'
AND country IN (
SELECT
column_value
FROM
TABLE ( json_doc )
)
)
WHERE
1=1
) a
WHERE
ROWNUM <= l_end_row
)
WHERE
rn >= l_start_row;
TYPE rec_attendee_data IS
TABLE OF cur_attendee_data%rowtype INDEX BY PLS_INTEGER;
l_cur_attendee_data rec_attendee_data;
BEGIN
dbms_output.put_line(l_country_array.count);
out_attendee_tab := return_attendee_arr_result();
OPEN cur_attendee_data;
LOOP
FETCH cur_attendee_data BULK COLLECT INTO l_cur_attendee_data;
EXIT WHEN l_cur_attendee_data.count = 0;
dbms_output.put_line('here in first insert');
lrec := return_attendee_report();
out_attendee_tab := return_attendee_arr_result(return_attendee_report());
out_attendee_tab.DELETE;
FOR i IN 1..l_cur_attendee_data.count LOOP
-- dbms_output.put_line('Inside cursor ' );
BEGIN
l_num_counter := l_num_counter + 1;
lrec := return_attendee_report();
lrec.requestid := l_cur_attendee_data(i).request_id;
lrec.attendeetype := l_cur_attendee_data(i).attendee_type;
lrec.attendeetype := json_doc;
IF l_num_counter > 1 THEN
out_attendee_tab.extend();
out_attendee_tab(l_num_counter) := return_attendee_report();
ELSE
out_attendee_tab := return_attendee_arr_result(return_attendee_report());
END IF;
out_attendee_tab(l_num_counter) := lrec;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error occurred : ' || sqlerrm);
END;
END LOOP;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('HERE INSIIDE OTHERS' || sqlerrm);
END;
Whenever j"son_doc" is null we need to skip the in clause. Is this possible, let me know if we have any solution.
user will pass jin_son_doc will be like this "India, America".
by using the following function i'm converting string to array,
create or replace FUNCTION fn_varchar_to_array(p_list IN VARCHAR2)
RETURN CHAR_ARRAY
AS
l_string VARCHAR2(32767) := p_list || ',';
l_comma_index PLS_INTEGER;
l_index PLS_INTEGER := 1;
l_tab CHAR_ARRAY := CHAR_ARRAY();
BEGIN
LOOP
l_comma_index := INSTR(l_string, ',', l_index);
EXIT WHEN l_comma_index = 0;
l_tab.EXTEND;
l_tab(l_tab.COUNT) := SUBSTR(l_string, l_index, l_comma_index - l_index);
l_index := l_comma_index + 1;
END LOOP;
RETURN l_tab;
END fn_varchar_to_array;
You can use OR condition as following:
....
AND (json_doc is null
OR country IN (
SELECT
column_value
FROM
TABLE ( json_doc )
)
)
...
Cheers!!

Column moving in Oracle Pl/Sql with for loop

For example, I want to move my 2 Column between for example KW_01 (dropdown) and KW_03 (dropdown) to between KW_04 (dropdown) and KW_06 (dropdown). I have 53 column in a table. I wrote code (see below) but unfortunately it does not work properly. He does that when I start a code.
Unexpected results:
Outer Loop counter is kw_04 Inner Loop counter is 1
Outer Loop counter is kw_04 Inner Loop counter is 2
Outer Loop counter is kw_04 Inner Loop counter is 3
Outer Loop counter is kw_05 Inner Loop counter is 1
Outer Loop counter is kw_05 Inner Loop counter is 2
Outer Loop counter is kw_05 Inner Loop counter is 3
Outer Loop counter is kw_06 Inner Loop counter is 1
Outer Loop counter is kw_06 Inner Loop counter is 2
Outer Loop counter is kw_06 Inner Loop counter is 3
DECLARE
plsql VARCHAR2(500);
BEGIN
For i in (SELECT column_id
FROM alsi_bedarfsplanung unpivot(column_value FOR column_id IN("KW_01", "KW_02", "KW_03", "KW_04", "KW_05", "KW_06"))
WHERE column_id BETWEEN :drp1 AND :drp2
and id = 1)
LOOP
FOR o in (SELECT column_value
FROM alsi_bedarfsplanung unpivot(column_value FOR column_id IN("KW_01", "KW_02", "KW_03", "KW_04", "KW_05", "KW_06"))
WHERE column_id BETWEEN :drp3 AND :drp4
and id = 1)
LOOP
plsql := ' UPDATE ALSI_BEDARFSPLANUNG SET ' || i.column_id || ' = ' ||
o.column_value || ' where ID = 1 ';
EXECUTE IMMEDIATE plsql;
END LOOP;
END LOOP;
END;
My DB
What i want,
Outer Loop counter is kw_04 Inner Loop counter is 1//(KW_1 Value)
Outer Loop counter is kw_05 Inner Loop counter is 2//(KW_2 Value)
Outer Loop counter is kw_06 Inner Loop counter is 3//(KW_3 Value)
The problem is the way you're looping within a loop; what you actually need to do is identify the columns to update to and from separately, and then loop over each set of columns to do the updates.
Even better would be to do all the work in a single update, like so:
-- should error with "Invalid columns specified" due to final proc call,
-- but should update the two rows accordingly
DECLARE
TYPE col_array IS TABLE OF VARCHAR2(30) INDEX BY pls_INTEGER;
v_cols_to_update_arry col_array;
v_cols_update_from_arry col_array;
PROCEDURE update_cols (p_id IN INTEGER,
p_drp1 IN VARCHAR2,
p_drp2 IN VARCHAR2,
p_drp3 IN VARCHAR2,
p_drp4 IN VARCHAR2)
IS
v_sql CLOB := 'UPDATE alsi_bedarfsplanung SET '||CHR(10);
BEGIN
SELECT column_id
BULK COLLECT INTO v_cols_to_update_arry
FROM alsi_bedarfsplanung
UNPIVOT (column_val FOR column_id IN (kw_01, kw_02, kw_03, kw_04, kw_05, kw_06, kw_07, kw_08))
WHERE column_id BETWEEN p_drp1 AND p_drp2
AND id = p_id;
SELECT column_id
BULK COLLECT INTO v_cols_update_from_arry
FROM alsi_bedarfsplanung
UNPIVOT (column_val FOR column_id IN (kw_01, kw_02, kw_03, kw_04, kw_05, kw_06, kw_07, kw_08))
WHERE column_id BETWEEN p_drp3 AND p_drp4
AND id = p_id;
IF v_cols_to_update_arry.count > 0
AND v_cols_update_from_arry.count > 0
AND v_cols_to_update_arry.count = v_cols_update_from_arry.count THEN
FOR i IN 1..v_cols_to_update_arry.count
LOOP
if i = 1 then
v_sql := v_sql || ' ' || v_cols_to_update_arry(i) || ' = ' || v_cols_update_from_arry(i);
else
v_sql := v_sql || ',' || CHR(10) || ' ' || v_cols_to_update_arry(i) || ' = ' || v_cols_update_from_arry(i);
end if;
END LOOP;
v_sql := v_sql || chr(10) || 'where id = :p_id';
EXECUTE IMMEDIATE v_sql USING p_id;
ELSE
raise_application_error(-20001, 'Invalid columns specified');
END IF;
END update_cols;
BEGIN
update_cols (p_id => 1,
p_drp1 => 'KW_04',
p_drp2 => 'KW_06',
p_drp3 => 'KW_01',
p_drp4 => 'KW_03');
COMMIT;
update_cols (p_id => 2,
p_drp1 => 'KW_05',
p_drp2 => 'KW_08',
p_drp3 => 'KW_01',
p_drp4 => 'KW_04');
COMMIT;
update_cols (p_id => 1,
p_drp1 => 'KW_01',
p_drp2 => 'KW_02',
p_drp3 => 'KW_05',
p_drp4 => 'KW_05');
END;
/
This works by fetching each list of columns into a separate array, looping over the arrays to build up the list of columns being updated, before concatenating that into the update statement.
Here's a demo of it working

Select into a variable with case statement in a for loop

The foo variable should be filled with a select case within a for loop and then put out. I used a goto end_loop reference inside an exception, so the loop can continue.
Before I put the exception, I had an ORA-01403 error. Now I have an ORA-01422 error. The other selects without the case statement worked fine.
declare
foo varchar2(2000);
BEGIN
FOR rec IN (SELECT something FROM somewhere)
LOOP
BEGIN
Select case when attribute = 'something' then '1' end into foo from somewhere where some_condition;
DBMS_OUTPUT.put_line( 'Something' || foo);
EXCEPTION
WHEN NO_DATA_FOUND THEN
foo := NULL;
goto end_loop;
END;
<<end_loop>>
null;
END LOOP;
END;
Edit
More detailed
declare
opdatum varchar2(2000);
opdiagnose varchar2(2000);
d_op varchar2(2000);
some_variable varchar2(2000);
BEGIN
FOR rec IN (SELECT p.name, p.vorname, p.geburtsdatum, a.kis_id, kg.kg_id FROM kg_eintraege kg
INNER JOIN aufenthalte a
ON kg.patient_nr = a.patient_nr
and kg.fall_nr = a.fall_nr
INNER JOIN personen p
ON a.patient_nr = p.pat_nr
WHERE kg.kgtitel_nr = xxxxxxa
and a.kis_id = xxxxxxb)
LOOP
BEGIN
Select kurztext into opdatum from kg_eintraege where kontext = rec.kg_id and kgtitel_nr = xxxxxxc;
Select text into opdiagnose from kg_eintraege where kontext = rec.kg_id and kgtitel_nr = xxxxxxd;
Select text into d_op from kg_eintraege where kontext = rec.kg_id and kgtitel_nr = xxxxxxe;
Select case when kurztext = 'Something' then '1' end into some_variable from kg_eintraege where kontext = rec.kg_id and kgtitel_nr = xxxxxxf;
DBMS_OUTPUT.put_line(rec.name || ' ' || rec.vorname || ' ' || TO_CHAR(rec.geburtsdatum, 'DD.MM.YYYY')
|| ' ' || rec.kis_id || ' ' || opdatum|| ' ' || opdiagnose ||
' ' || d_op || ' ' || some_variable
);
EXCEPTION
WHEN NO_DATA_FOUND THEN
some_variable := NULL;
goto end_loop;
END;
<<end_loop>>
null;
END LOOP;
END;
Update
The case statement seems to be alright. The problem is that some rows in the select are null.
Update2
No exception needed.
Solution:
select nvl((select case when kurztext = 'Something' then '1' end from kg_eintraege where kontext = rec.kg_id and kgtitel_nr = xxxxxxf and kurztext = 'Something'), 'NOT_FOUND') into some_variable from dual
Thanks to NikNik for the help.
You problem is not the CASE but your WHERE condition witch is retourning more than 1 record or 0 record found.
For more details look here.
In the second case you can do this:
select nvl( (your_case), 'NOT_FOUND' ) into foo from dual;

Multiple FORALL in a orasql procedure

Im trying to both delete then update some data from a table inside a procedure. It is my understanding that both can't be done in the same FORALL statement and that I can do multiple FORALL using the same cursor. The problem is that the second FORALL does not seem to do anything. Is there something that im not getting? Here is the code :
cursor cPARTY is
SELECT /* +parallel(4) */ DISTINCT p.ID,
CASE WHEN sf.PARTYID is null THEN 'delete'
ELSE 'switch'
END AS action,
pa.SOURCESYSTEMLID as sources
FROM CV_CLAIMS_TRAVEL.EPUR_PARTY p
LEFT JOIN CV_CLAIMS_TRAVEL.STAR_FILE sf ON sf.PARTYID = p.ID
LEFT JOIN CV_CLAIMS_TRAVEL.PARTY pa ON pa.ID = p.ID;
type type_party is TABLE OF cPARTY%ROWTYPE INDEX BY PLS_INTEGER;
t_party type_party;
nLOT pls_integer := 1;
nbDeleted int :=0;
nbSwitched int := 0;
begin
p_tableName := 'PARTY(INDIVIDU)';
allBEGIN_TIMESTAMP := systimestamp;
open cPARTY;
loop
lotBEGIN_TIMESTAMP := systimestamp;
dbms_application_info.set_module('CV_CLAIMS_TRAVEL.PARTY',trim(to_char(nLOT * nLIMIT,'999G999G999')));
FETCH cPARTY BULK COLLECT
INTO t_party
limit nLIMIT;
exit when t_party.count = 0;
p_nbLinesTransfered :='Erreur: Suppression de données';
dbms_application_info.set_module('CV_CLAIMS_TRAVEL.PARTY - DELETING',trim(to_char(nLOT * nLIMIT,'999G999G999')));
FORALL i IN t_party.FIRST .. t_party.LAST
DELETE /*+parallel(4)*/ FROM CV_CLAIMS_TRAVEL.PARTY
WHERE ID = t_party(i).ID
AND t_party(i).action = 'delete';
nbDeleted := nbDeleted + sql%rowcount;
FORALL i IN t_party.FIRST .. t_party.LAST
UPDATE CV_CLAIMS_TRAVEL.PARTY
SET UPDATEDATE = sysdate, SOURCESYSTEMLID = 'SOURCE_SYSTEM:0000000000', UPDATEDBYUSERID = 'CV_CLAIM_INTEG'
WHERE ID = t_party(i).ID
AND t_party(i).sources='SOURCE_SYSTEM:0000000004'
AND t_party(i).action = 'switch';
nbSwitched := nbSwitched + sql%rowcount;
commit;
lotEND_TIMESTAMP :=systimestamp;
trc.trc_message('lotELAPSED '||to_char(nLOT * nLIMIT,'999G999G990')||' Rows. ELAPSED '|| replace(substr(to_char(lotEND_TIMESTAMP - lotBEGIN_TIMESTAMP, 'HH24:MI:SS.FF3'),1,20),'+000000 ','+'));
nLOT := nLOT + 1;
end loop;
close cPARTY;
commit;
gather_stats('CV_CLAIMS_TRAVEL', 'PARTY');