E-mail Formatting Oracle - sql

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
...

Related

I am able to compile the code but it gives me an error of an sql command. How can I fix this?

I was able to write a section of code to delete a customer from the table given the customer email, unfortunately I am running into an error and do not know how to. I am beginner.
Here is my code:
CREATE OR REPLACE PROCEDURE DELETE_CUSTOMER(C_EMAIL IN VARCHAR2)
IS
CURSOR CUSTOMERS_CURSOR IS SELECT * FROM CUSTOMER
WHERE CUSTOMER_OWNER_ID = C_EMAIL);
V_ROW CUSTOMERS_CURSOR%ROWTYPE;
DELETE_COUNT INTEGER := 0;
BEGIN
FOR V_ROW IN CUSTOMERS_CURSOR LOOP
DELETE FROM CUSTOMER WHERE CUSTOMER_EMAIL = V_ROW.CUSTOMER_EMAIL;
DELETE_CUSTOMER := DELETE_CUSTOMER + 1;
END LOOP;
IF DELETE_CUSTOMER = 0 THEN
DBMS_OUTPUT.PUT_LINE('No customer has this email in our records thus ' ||
C_EMAIL || ', 0 rows deleted.');
ELSE
DBMS_OUTPUT.PUT_LINE(DELETE_CUSTOMER || ' email deleted.');
END IF;
END;
The error seems to tell you that there's an extra closing parenthesis on line 3, at the end of customers_cursor declaration.
Just remove it.
CREATE OR REPLACE PROCEDURE DELETE_CUSTOMER(C_EMAIL IN VARCHAR2)
IS
CURSOR CUSTOMERS_CURSOR IS SELECT * FROM CUSTOMER
WHERE CUSTOMER_OWNER_ID = C_EMAIL;
Also, lines with delete_customer variable seemed to be wrong.. maybe you are trying to refer to the delete_count variable?
delete_count := delete_count + 1;
IF delete_count = 0 THEN
...
DBMS_OUTPUT.PUT_LINE(delete_count || ' email deleted.');
After fixing stuffs, your final procedure description should be like this:
CREATE OR REPLACE PROCEDURE DELETE_CUSTOMER(C_EMAIL IN VARCHAR2)
IS
CURSOR CUSTOMERS_CURSOR IS SELECT * FROM CUSTOMER
WHERE CUSTOMER_OWNER_ID = C_EMAIL;
V_ROW CUSTOMERS_CURSOR%ROWTYPE;
DELETE_COUNT INTEGER := 0;
BEGIN
FOR V_ROW IN CUSTOMERS_CURSOR LOOP
DELETE FROM CUSTOMER WHERE CUSTOMER_EMAIL = V_ROW.CUSTOMER_EMAIL;
DELETE_COUNT := DELETE_COUNT + 1;
END LOOP;
IF DELETE_COUNT = 0 THEN
DBMS_OUTPUT.PUT_LINE('No customer has this email in our records thus ' ||
C_EMAIL || ', 0 rows deleted.');
ELSE
DBMS_OUTPUT.PUT_LINE(DELETE_COUNT || ' email deleted.');
END IF;
END;

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!!

How to validate and print message when there is no data? PL SQL

Using PL/SQL I'm trying to validate and print a message when there's no data found on a cursor. My main problem is that if I use the %NOTFOUND it gets printed multiple times or along when data is found.
Here is my code:
set SERVEROUTPUT ON
set verify off
DECLARE
rut int;
CURSOR Ejercicio2 (rut int)
IS
SELECT alumno.nombre,alumno.apellidoP,alumno.apellidoM,Ramo.descripcion,profesor.nombre
FROM alumno
INNER JOIN alumnoramo ON alumnoramo.cod_matricula = alumno.cod_matricula
INNER JOIN Ramo ON ramo.cod_ramo = alumnoramo.cod_ramo
INNER JOIN profesor ON profesor.cod_prof = ramo.cod_prof
WHERE alumno.cod_matricula = rut;
alumno_nombre VARCHAR2(45);
alumno_apellido VARCHAR2(45);
alumno_apellidoM VARCHAR2(45);
ramo_nombre VARCHAR2(45);
profesor_nombre VARCHAR2(45);
BEGIN
rut := '&rut';
OPEN Ejercicio2 (rut);
LOOP
FETCH Ejercicio2 INTO alumno_nombre,alumno_apellido,alumno_apellidoM,ramo_nombre,profesor_nombre;
EXIT WHEN Ejercicio2%NOTFOUND;
dbms_output.put_line('Nombre: ' || alumno_nombre);
dbms_output.put_line('Apellido: ' || alumno_apellido);
dbms_output.put_line('Apellido Materno: ' || alumno_apellidoM);
dbms_output.put_line('Ramo: ' || ramo_nombre);
dbms_output.put_line('Profesor: ' || profesor_nombre);
END LOOP;
CLOSE Ejercicio2;
END;
When the user inputs a "rut" it should normally print the found data and end. If the input "rut" and no data is returned, then it should print a message and ending the program. I haven't being able to do so.
use the below code block .let me know if you get some error.I just wrote it on notepad and it should as I expect.
set SERVEROUTPUT ON
set verify off
DECLARE
rut int;
CURSOR Ejercicio2 (rut int)
IS
SELECT alumno.nombre,alumno.apellidoP,alumno.apellidoM,Ramo.descripcion,profesor.nombre
FROM alumno
INNER JOIN alumnoramo ON alumnoramo.cod_matricula = alumno.cod_matricula
INNER JOIN Ramo ON ramo.cod_ramo = alumnoramo.cod_ramo
INNER JOIN profesor ON profesor.cod_prof = ramo.cod_prof
WHERE alumno.cod_matricula = rut;
TYPE Ejercicio2_typ IS TABLE OF Ejercicio2%ROWTYPE;
Ejercicio2_tbl Ejercicio2_typ;
BEGIN
rut := '&rut';
OPEN Ejercicio2 (rut);
FETCH Ejercicio2 BULK COLLECT INTO Ejercicio2_tbl;
IF Ejercicio2_tbl.count >0 THEN
FOR rec IN Ejercicio2_tbl.first..Ejercicio2_tbl.last LOOP
dbms_output.put_line('Nombre: ' || Ejercicio2_tbl(rec).alumno_nombre);
dbms_output.put_line('Apellido: ' || Ejercicio2_tbl(rec).alumno_apellido);
dbms_output.put_line('Apellido Materno: ' || Ejercicio2_tbl(rec).alumno_apellidoM);
dbms_output.put_line('Ramo: ' || Ejercicio2_tbl(rec).ramo_nombre);
dbms_output.put_line('Profesor: ' || Ejercicio2_tbl(rec).profesor_nombre);
END LOOP;
ELSE
dbms_output.put_line('No data found');
END IF;
CLOSE Ejercicio2;
END;
/
Happy coding.
Mark it as an answer if it satisfy your needs.
Just a variation and a clean way of handling the scenario. Hope it helps.
CREATE OR REPLACE TYPE obj IS OBJECT
(
nombre VARCHAR2(100),
apellidoP VARCHAR2(100)
apellidoM VARCHAR2(100)
descripcion VARCHAR2(100)
nombre VARCHAR2(100)
);
CREATE OR REPLACE TYPE tab IS TABLE OF obj;
SET SERVEROUTPUT ON
SET verify OFF
DECLARE
rut INT:=&Enter_rut;
tab1 tab;
BEGIN
SELECT obj(alumno.nombre,alumno.apellidoP,alumno.apellidoM,Ramo.descripcion,profesor.nombre) BULK COLLECT
INTO tab1
FROM alumno
INNER JOIN alumnoramo
ON alumnoramo.cod_matricula = alumno.cod_matricula
INNER JOIN Ramo
ON ramo.cod_ramo = alumnoramo.cod_ramo
INNER JOIN profesor
ON profesor.cod_prof = ramo.cod_prof
WHERE alumno.cod_matricula = rut;
IF tab1.EXISTS(1) THEN
FOR I IN tab1.FIRST..tab1.LAST
LOOP
dbms_output.put_line('Nombre: ' || tab1(i).nombre);
dbms_output.put_line('Apellido: ' || tab1(i).apellidoP);
dbms_output.put_line('Apellido Materno: ' || tab1(i).apellidoM);
dbms_output.put_line('Ramo: ' || tab1(i).descripcion);
dbms_output.put_line('Profesor: ' || tab1(i).nombre);
END LOOP;
ELSE
dbms_output.put_line('no data found for the Input');
END IF;
END;
You could set a Boolean variable in the loop, and then check at the end whether it was true or false:
set define on
accept rut number prompt 'Introduza un identificador de class: '
var rut number
exec :rut := &rut
declare
cursor ejercicio2
( cp_rut int )
is
select alumno.nombre as alumno_nombre
, alumno.apellidop as alumno_apellido
, alumno.apellidom as alumno_apellidom
, ramo.descripcion as ramo_nombre
, profesor.nombre as profesor_nombre
from alumno
join alumnoramo
on alumnoramo.cod_matricula = alumno.cod_matricula
join ramo
on ramo.cod_ramo = alumnoramo.cod_ramo
join profesor
on profesor.cod_prof = ramo.cod_prof
where alumno.cod_matricula = cp_rut;
l_encontro boolean := false;
begin
for r in ejercicio2(:rut)
loop
l_encontro := true;
dbms_output.put_line('Nombre: ' || r.alumno_nombre);
dbms_output.put_line('Apellido: ' || r.alumno_apellido);
dbms_output.put_line('Apellido Materno: ' || r.alumno_apellidom);
dbms_output.put_line('Ramo: ' || r.ramo_nombre);
dbms_output.put_line('Profesor: ' || r.profesor_nombre);
end loop;
if not l_encontro then
dbms_output.put_line('No se encontraron las classes por rut ' || :rut);
end if;
end;
/
(Excuse my Google Spanish.)
Or you could make it a numeric value initialised to 0 and report the number of rows processed.

Procedure takes several hours to complete

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.

ORA-06550: line 1, column 7 (PL/SQL: Statement ignored) Error

I am getting following error for the stored procedure and not able to understand the issue (must be from db side) While googling, I found similar issues but couldn't get the solution. Can any one help me please find the error in PROCEDURE ??
Error :-
18:58:50,281 ERROR [STDERR] java.sql.SQLException: ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'SP_DIST_RETAILER_REMAP'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
Stored Prodedure(SP_DIST_RETAILER_REMAP) :-
CREATE OR REPLACE PROCEDURE SMAPRD02.SP_DIST_RETAILER_REMAP (
i_old_dist_code IN VARCHAR2,
i_new_dist_code IN VARCHAR2,
i_territory_remapping IN NUMBER,
i_remapping_reason IN VARCHAR2,
i_trans_doneby_rolename IN VARCHAR2,
i_trans_doneby_id IN NUMBER,
i_trans_dist_rolename IN VARCHAR2,
i_trans_ret_rolename IN VARCHAR2,
i_activity_type IN VARCHAR2,
i_ret_list IN V_ARRAY,
result OUT VARCHAR2,
i_o_query OUT VARCHAR2
)
AS
--i_ret_codes OUT VARCHAR2;
v_dist_count NUMBER;
v_ret_count NUMBER;
v_ret_codes VARCHAR2(10000) := '';
v_flag VARCHAR2(10) := 'true';
v_trans_id NUMBER;
v_query VARCHAR2(10000);
BEGIN
IF i_territory_remapping = 1 then
SELECT count(*) into v_dist_count FROM tblemployee where EMPCODE = i_new_dist_code and circle_code = (select emp.circle_code
from tblemployee emp where emp.empcode = i_old_dist_code) and upper(user_type) like upper('%dist%') and upper(ACCESS_TO) in ('SALES','BOTH') and upper(stage) not in (upper('InActive'));
ELSE
SELECT count(*) into v_dist_count FROM tblemployee where EMPCODE = i_new_dist_code and circle_code = (select emp.circle_code from tblemployee emp
where emp.empcode = i_old_dist_code) and cluster_code = (select emp.cluster_code from tblemployee emp where emp.empcode = i_old_dist_code)
and upper(user_type) like upper('%dist%') and upper(ACCESS_TO) in ('SALES','BOTH') and upper(stage) not in (upper('InActive'));
END IF;
IF v_dist_count =0 THEN
result := 'invalid_new_dist_code';
v_flag := 'false';
ELSIF v_dist_count = 1 THEN
SELECT count(*) into v_ret_count FROM tblretailer t where t.DIST_CODE = i_old_dist_code and (upper(t.ACCESS_TO) = 'SALES' or upper(t.ACCESS_TO) = 'BOTH');
--SELECT count(*) into v_ret_count FROM tblretailer t where t.DIST_CODE = i_old_dist_code and upper(t.ACCESS_TO) = 'SALES' and upper(t.stage) in ('APPROVED','INACTIVE');
IF v_ret_count=i_ret_list.count THEN
IF i_territory_remapping = 1 THEN
result := 'no_ret_left';
v_flag := 'false';
END IF;
ELSE
IF i_territory_remapping != 1 THEN
result := 'ret_left';
v_flag := 'false';
END IF;
END IF;
END IF;
IF i_ret_list is null or i_ret_list.count = 0 THEN
result := 'empty retailers list';
v_flag := 'false';
END IF;
/*FOR i IN i_ret_list.FIRST .. i_ret_list.LAST
LOOP
IF v_ret_codes is null
THEN
v_ret_codes := ''''||i_ret_list(i)||'''';
ELSE
v_ret_codes := v_ret_codes||','''||i_ret_list(i)||'''';
END IF;
IF v_ret_codes is null
THEN
v_ret_codes := i_ret_list(i);
ELSE
v_ret_codes := v_ret_codes||','||i_ret_list(i);
END IF;
END LOOP;
i_ret_codes := v_ret_codes;
v_flag := 'false';
result := 'success';*/
IF v_flag = 'true' THEN
FOR i IN i_ret_list.FIRST .. i_ret_list.LAST
LOOP
IF v_ret_codes is null
THEN
v_ret_codes := ''''||i_ret_list(i)||'''';
ELSE
v_ret_codes := v_ret_codes||','''||i_ret_list(i)||'''';
END IF;
END LOOP;
--i_ret_codes := v_ret_codes;
--update tblretailer set dist_code=i_new_dist_code,DIST_ID=to_number(i_new_dist_code),cluster_code=(select cluster_code from tblemployee where empcode = i_new_dist_code),FOSID='',FOS_CODE='',DSR_ID='',DSR_CODE='',LAST_UPDATED_DATE=sysdate where retcode in (v_ret_codes);
v_query := 'update tblretailer set dist_code='||i_new_dist_code||',DIST_ID=to_number('||i_new_dist_code||'),cluster_code=(select cluster_code from tblemployee where empcode = '||i_new_dist_code||'),FOSID='''',FOS_CODE='''',DSR_ID='''',DSR_CODE='''',LAST_UPDATED_DATE=sysdate where retcode in ('||v_ret_codes||')';
execute immediate (v_query);
--i_query :='update tblretailer set dist_code='||i_new_dist_code||',DIST_ID=to_number('||i_new_dist_code||'),cluster_code=(select cluster_code from tblemployee where empcode = '||i_new_dist_code||'),FOSID='',FOS_CODE='',DSR_ID='',DSR_CODE='',LAST_UPDATED_DATE=sysdate where retcode in ('||v_ret_codes||');';
insert into TBL_TRANSFER_SUP_MASTER(MASTER_ID,TRANS_ID,TRANS_DONEBY_ROLENAME,TRANS_DONEBY_ID,TRANS_FROM_ROLENAME,TRANS_FROM,TRANS_TO_ROLENAME,TRANS_TO,ACTIVITY_CODE,TRANS_DATE,TRANSFER_REASON,LAST_UPDATED_DATE)
values(SUP_MASTER_TRANS_ID_SEQ.nextval,SUP_MASTER_TRANS_ID_SEQ.nextval,i_trans_doneby_rolename,i_trans_doneby_id,i_trans_dist_rolename,i_old_dist_code,i_trans_dist_rolename,i_new_dist_code,'101',sysdate,i_remapping_reason,sysdate) return TRANS_ID into v_trans_id;
FOR i IN i_ret_list.FIRST .. i_ret_list.LAST
LOOP
insert into TBL_TRANSFER_SUP_DTLS(DTLS_ID,TRANS_ID,TRANS_ON_ROLENAME,TRANS_ON_ID,LAST_UPDATED_DATE)
values(SUP_DTLS_ID_SEQ.nextval,v_trans_id,i_trans_ret_rolename,i_ret_list(i),sysdate);
END LOOP;
IF SQL%ROWCOUNT>0 THEN
result := 'success';
ELSE
result := 'failure';
END IF;
--update tblstock set NEW_DIST_CODE_REMAP=i_new_dist_code,REMAP_DATE=sysdate,LAST_UPDATED_DATE=sysdate where (DIST_CODE=i_old_dist_code or NEW_DIST_CODE_REMAP=i_old_dist_code) and RET_CODE in (v_ret_codes);
v_query := 'update tblstock set NEW_DIST_CODE_REMAP='||i_new_dist_code||',REMAP_DATE=sysdate,LAST_UPDATED_DATE=sysdate where (DIST_CODE='||i_old_dist_code||' or NEW_DIST_CODE_REMAP='||i_old_dist_code||') and RET_CODE in ('||v_ret_codes||')';
execute immediate (v_query);
i_o_query := v_query;
insert all into TBL_ACTIVITY_LOG (LOG_ID,TRANS_ID,ACTIVITY_DONEBY_ROLENAME,ACTIVITY_DONEBY_ID,ACTIVITY_REFERENCE_ID,ACTIVITY_CODE,ACTIVITY_DATE)
values(ACTIVITY_LOG_TRANS_ID_SEQ.NEXTVAL,ACTIVITY_LOG_TRANS_ID_SEQ.NEXTVAL,i_trans_doneby_rolename,i_trans_doneby_id,v_trans_id,
act_code,sysdate) select log_config.ACTIVITY_CODE act_code from TBL_ACTIVITY_LOG_CONFIG log_config
where upper(log_config.ACTIVITY_TYPE)= upper(i_activity_type);
END IF;
END;
/
Java Code :-
try{
if(ret_list.size()>0)
ret_code = ret_list.toArray();
con = ConnectionManager.getDirectConnection();
ArrayDescriptor descriptor = ArrayDescriptor.createDescriptor(PropertyLoader.RET_SECONDARY_V_ARRAY,con);
ARRAY array_to_pass = new ARRAY( descriptor,con, ret_code );
cstmt = con.prepareCall("{ call SP_DIST_RETAILER_REMAP(?,?,?,?,?,?,?,?,?,?,?,?)}");
cstmt.setString(1,old_dist_code.trim());
cstmt.setString(2,new_dist_code.trim());
if(territory_remapping)
cstmt.setInt(3,1);
else
cstmt.setInt(3,2);
cstmt.setString(4,remapping_reason);
cstmt.setString(5,userVO.getRolename().trim());
cstmt.setInt(6,userVO.getEmpid());
cstmt.setString(7,PropertyLoader.DISTRIBUOTR_ROLENAME);
cstmt.setString(8,PropertyLoader.RETAILER_ROLENAME);
cstmt.setString(9,PropertyLoader.ACTIVITY_TYPES_RETAILER_REMAPPING);
cstmt.setArray(10,array_to_pass);
cstmt.registerOutParameter(11,Types.VARCHAR);
cstmt.registerOutParameter(12,Types.VARCHAR);
/*cstmt.registerOutParameter(13,Types.VARCHAR);*/
cstmt.execute();
status = cstmt.getString(11);
System.out.println("Remap Update Query "+cstmt.getString(12));
//System.out.println(cstmt.getString(13));
}
If the value stored in PropertyLoader.RET_SECONDARY_V_ARRAY is not "V_ARRAY", then you are using different types; even if they are declared identically (e.g. both are table of number) this will not work.
You're hitting this data type compatibility restriction:
You can assign a collection to a collection variable only if they have
the same data type. Having the same element type is not enough.
You're trying to call the procedure with a parameter that is a different type to the one it's expecting, which is what the error message is telling you.
The procedure which you are using is should be properly declared in the place which you are using it. For an example if it is under a user and in a package then it should be in that order. The username, package and procedurename.