How to create dynamic cursor in PLSQL - Oracle - oracle

I cannot create this cursor dynamically, I only have to modify the name of the table in the statement. But it returns me error.
What am I doing wrong or what am I missing to create the dynamic cursor?
The dynamic statement is in the Lv_SQL variable and I call the cursor C_DATOS but it does not recognize it.
PROCEDURE PROC_CAB_DET(Pv_corte VARCHAR2, Pv_MsjError IN OUT VARCHAR2) IS
Lv_Table VARCHAR2(100);
Lv_SQL VARCHAR2(5000);
C_DATOS SYS_REFCURSOR;
BEGIN
Lv_Table := NULL;
IF (Pv_corte IN ('02', '03')) THEN
Lv_Table := 'TABLE_TMP_MOV';
ELSIF (Pv_corte IN ('14', '15')) THEN
Lv_Table := 'TABLE_TMP_FIX';
ELSE
Lv_Table := 'TABLE_TMP_CMF';
END IF;
Lv_SQL := 'SELECT cuenta, campo_2 RUBRO
FROM ' || Lv_Table || '
WHERE codigo = 1
AND CAMPO_3 != "000"
AND (campo_2 NOT IN (SELECT RUBRO FROM GSI_QC_RUBROS_CABECERA)
AND upper(campo_2) NOT LIKE "NAN%")
MINUS
SELECT cuenta, campo_2 RUBRO
FROM ' || Lv_Table || '
WHERE codigo=4
AND campo_2 != "ICE (12%)"';
OPEN C_DATOS FOR Lv_SQL;
FOR I IN C_DATOS LOOP
INSERT INTO GSI_QC_CBS_CASOS_ERROR(CUENTA, ID_ESCENARIO, DATO_TMP_1)
VALUES(I.CUENTA, 'IdEscenario', 'DATA');
END LOOP;
COMMIT;
CLOSE C_DATOS;
EXCEPTION
WHEN OTHERS THEN
Pv_MsjError := SQLERRM;
END PROC_CAB_DET;
PLS-00221: C_DATOS is not a procedure or is undefined

You can't enclose strings into double quotes; have to be single ones. To make it simpler, use the q-quoting mechanism. Also, you wrongly looped through refcursor.
I created dummy tables to make that procedure compile; I don't know whether code does what you planned.
SQL> create or replace
2 PROCEDURE PROC_CAB_DET(Pv_corte VARCHAR2, Pv_MsjError IN OUT VARCHAR2) IS
3 Lv_Table VARCHAR2(100);
4 Lv_SQL VARCHAR2(5000);
5 C_DATOS SYS_REFCURSOR;
6 --
7 l_cuenta table_tmp_mov.cuenta%type;
8 l_rubro table_tmp_mov.campo_2%type;
9 BEGIN
10 Lv_Table := NULL;
11 IF (Pv_corte IN ('02', '03')) THEN
12 Lv_Table := 'TABLE_TMP_MOV';
13 ELSIF (Pv_corte IN ('14', '15')) THEN
14 Lv_Table := 'TABLE_TMP_FIX';
15 ELSE
16 Lv_Table := 'TABLE_TMP_CMF';
17 END IF;
18
19 Lv_SQL := 'SELECT cuenta, campo_2 RUBRO
20 FROM ' || Lv_Table || q'[
21 WHERE codigo = 1
22 AND CAMPO_3 != '000'
23 AND (campo_2 NOT IN (SELECT RUBRO FROM GSI_QC_RUBROS_CABECERA)
24 AND upper(campo_2) NOT LIKE 'NAN%')
25 MINUS
26 SELECT cuenta, campo_2 RUBRO
27 FROM ]' || Lv_Table || q'[
28 WHERE codigo=4
29 AND campo_2 != 'ICE (12%)']';
30
31 OPEN C_DATOS FOR Lv_SQL;
32
33 loop
34 fetch c_datos into l_cuenta, l_rubro;
35 exit when c_datos%notfound;
36
37 INSERT INTO GSI_QC_CBS_CASOS_ERROR(CUENTA, ID_ESCENARIO, DATO_TMP_1)
38 VALUES(l_CUENTA, 'IdEscenario', 'DATA');
39 END LOOP;
40 COMMIT;
41
42 CLOSE C_DATOS;
43
44 EXCEPTION
45 WHEN OTHERS THEN
46 Pv_MsjError := SQLERRM;
47 END PROC_CAB_DET;
48 /
Procedure created.
Let's run it:
SQL> set serveroutput on;
SQL> declare
2 l_err varchar2(200);
3 begin
4 proc_cab_det('02', l_err);
5 dbms_output.put_line('error = ' || l_err);
6 end;
7 /
error =
PL/SQL procedure successfully completed.
SQL>

Replace " inside your lv_SQL string with doubled single quotes, ''

Related

Error passing an Oracle cursor when trying to test print its contents

We're using Oracle 12c.
Passing a cursor from a procedure. Trying to test print its contents.
I get the following error message:
ORA-01001: invalid cursor
ORA-06512: at line 25
Why is the cursor invalid?
Here's the code.
SET SERVEROUTPUT ON
--VARIABLE X REFCURSOR;
DECLARE
RUN_DATE VARCHAR2 (10);
D_XMAS_NY VARCHAR2 (10);
PO_ERROR_CODE_N NUMBER;
PO_ERROR_MESSAGE_C VARCHAR2 (32767);
PO_REF_CUR SLD_COMMON_PKG.PG_COMMON_REFCUR;
V_VAL SLDPROC.t_sld_gic_repo_nonrepo_rec%ROWTYPE;
BEGIN
RUN_DATE := '2022-07-27';
D_XMAS_NY := '9999-12-30';
PO_ERROR_CODE_N := NULL;
PO_ERROR_MESSAGE_C := NULL;
-- PO_REF_CUR := NULL;
SLDPROC.SP_SLD_GEN_GIC_REINV_DET (RUN_DATE,
D_XMAS_NY,
PO_ERROR_CODE_N ,
PO_ERROR_MESSAGE_C,
PO_REF_CUR);
LOOP
FETCH PO_REF_CUR INTO V_VAL;
EXIT WHEN PO_REF_CUR%NOTFOUND;
/*Notice the DBMS_OUTPUT line is commented out. So at this point, Oracle is just running through the cursor.*/
--DBMS_OUTPUT.PUT_LINE( V_VAL.d_inc_dt );
END LOOP;
CLOSE PO_REF_CUR;
END;
I get the following error message:
ORA-01001: invalid cursor
ORA-06512: at line 25
The Procedure SLDPROC.SP_SLD_GEN_GIC_REINV_DET compiles correctly and the cursor inside the procedure is correct. Finally when I run this procedure without any trace of the Cursor Loop it finishes correctly. It's when I try to list out the contents of the cursor.
The contents of the cursor consist of 1 giant column with all the columns from a table concatenated together like this.
OPEN po_ref_cur FOR
SELECT c_run_type
|| ','
|| TO_CHAR(d_inc_dt, 'DD/MM/YYYY')
|| ','
|| lend_agnt
|| ','
|| trim(ACCNT)
|| ','
|| NVL(trim(DAY_CT), '<NULL>') -- DAY_CT
|| ','
|| NVL(trim(REPOCP_LEI_CODE), '<NULL>') -- REPOCP_LEI_CODE
|| ','
|| NVL(trim(REPOCP_BR_DESC), '<NULL>')
FROM t_sld_gic_repo_nonrepo_rec
ORDER BY c_run_type,d_inc_dt, NVL(issuer_repocp, 'ZZ');
SP_SLD_GEN_GIC_REINV_DET procedure's last parameter should be OUT, returning a ref cursor. Is it?
Because, if I try to mimic what you did, that code works.
Sample procedure:
SQL> CREATE OR REPLACE PROCEDURE SP_SLD_GEN_GIC_REINV_DET (
2 par_rc OUT SYS_REFCURSOR
3 ) IS
4 BEGIN
5 OPEN par_rc FOR SELECT dname FROM dept;
6 END;
7 /
Procedure created.
SQL>
Your anonymous PL/SQL block (slightly modified):
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 run_date VARCHAR2(10);
3 d_xmas_ny VARCHAR2(10);
4 po_error_code_n NUMBER;
5 po_error_message_c VARCHAR2(32767);
6 po_ref_cur SYS_REFCURSOR;-- SLD_COMMON_PKG.PG_COMMON_REFCUR;
7 v_val VARCHAR2(200); --SLDPROC.t_sld_gic_repo_nonrepo_rec%ROWTYPE;
8 BEGIN
9 run_date := '2022-07-27';
10 d_xmas_ny := '9999-12-30';
11 po_error_code_n := NULL;
12 po_error_message_c := NULL;
13
14 -- PO_REF_CUR := NULL;
15 -- SLDPROC.SP_SLD_GEN_GIC_REINV_DET (RUN_DATE,
16 -- D_XMAS_NY,
17 -- PO_ERROR_CODE_N ,
18 -- PO_ERROR_MESSAGE_C,
19 -- PO_REF_CUR);
20 SP_SLD_GEN_GIC_REINV_DET (po_ref_cur);
21 LOOP
22 FETCH po_ref_cur INTO v_val;
23 EXIT WHEN po_ref_cur%notfound;
24 /*Notice the DBMS_OUTPUT line is commented out. So at this point, Oracle is just running through the cursor.*/
25 DBMS_OUTPUT.PUT_LINE(V_VAL);
26 END LOOP;
27 CLOSE po_ref_cur;
28 END;
29 /
ACCOUNTING
RESEARCH
SALES
OPERATIONS
PL/SQL procedure successfully completed.
SQL>

Oracle PL/SQL issue: PLS-00306 : wrong number or types of arguments in call to

Today I have code I get error
PLS-00306: wrong number or types of arguments in call to
and I make sure the code working fine but when I use in dynamic code not worked
CREATE OR REPLACE PROCEDURE TB_DATA(P_TB_NAME VARCHAR2)
IS
V_COLUMNS VARCHAR2(32000) := GET_ALL_COLUMNS(P_TB_NAME) ;
V_COLUMNS_IN_LOOP VARCHAR2(32000) := 'I.'||REPLACE ( GET_ALL_COLUMNS(P_TB_NAME) , ',' , '||'',''||I.') ;
V_FILE UTL_FILE.FILE_TYPE ;
BEGIN
EXECUTE IMMEDIATE 'DECLARE
CURSOR C1 IS
SELECT '||V_COLUMNS || '
FROM '||P_TB_NAME || ';
BEGIN
' ||V_FILE ||' := UTL_FILE.FOPEN ( ''MY_DIR'' , ''TASK9.CSV'' , ''W'' ) ;
UTL_FILE.PUT_LINE ( '||V_FILE ||' , '|| V_COLUMNS||');
FOR I IN C1 LOOP
UTL_FILE.PUT_LINE ( '||V_FILE ||', '|| V_COLUMNS_IN_LOOP||') ;
END LOOP ;
END ;';
END ;
Function:
CREATE OR REPLACE FUNCTION HR.GET_ALL_COLUMNS (P_TABLE VARCHAR2)
RETURN VARCHAR2
IS
CURSOR C IS
SELECT *
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = P_TABLE ;
CURSOR C1 IS
SELECT *
FROM TAB
WHERE TNAME = P_TABLE ;
V_COLS VARCHAR2(32000);
V_COLS2 VARCHAR2(32000);
BEGIN
FOR I IN C LOOP
V_COLS := V_COLS ||','|| I.COLUMN_NAME ;
END LOOP ;
FOR V IN C1 LOOP
V_COLS2 := V_COLS2 ||','|| P_TABLE ;
END LOOP ;
RETURN LTRIM( V_COLS , ',') ;
END ;
I just need to know where is my mistake or what is missing.
The function is OK; it is procedure that fails because you have to declare V_FILE within the dynamic SQL part of code, not outside of it. Something like this:
SQL> CREATE OR REPLACE PROCEDURE TB_DATA (P_TB_NAME VARCHAR2)
2 IS
3 V_COLUMNS VARCHAR2 (32000) := GET_ALL_COLUMNS (P_TB_NAME);
4 V_COLUMNS_IN_LOOP VARCHAR2 (32000)
5 := 'I.' || REPLACE (GET_ALL_COLUMNS (P_TB_NAME), ',', '||'',''||I.');
6 L_STR VARCHAR2 (10000);
7 BEGIN
8 L_STR :=
9 'DECLARE
10 V_FILE UTL_FILE.FILE_TYPE;
11 CURSOR C1 IS
12 SELECT '
13 || V_COLUMNS
14 || '
15 FROM '
16 || P_TB_NAME
17 || ';
18 BEGIN
19 V_FILE := UTL_FILE.FOPEN ( ''MY_DIR'' , ''TASK9.CSV'' , ''W'' ) ;
20 FOR I IN C1 LOOP
21 UTL_FILE.PUT_LINE ( V_FILE, '
22 || V_COLUMNS_IN_LOOP
23 || ') ;
24 END LOOP ;
25 UTL_FILE.FCLOSE(V_FILE);
26 END ;';
27
28 EXECUTE IMMEDIATE L_STR;
29 END;
30 /
Procedure created.
Testing:
SQL> EXEC TB_DATA('DEPT');
PL/SQL procedure successfully completed.
SQL>

how to get the field name and value from a record dynamically

I have a procedure which receive as input parameter a record with 170 columns (it is based on the structure of a table).
In the procedure I want to call a debugging procedure one of whose parameters is a text string containing all the field names and values of this record.
For example:
CREATE OR REPLACE PROCEDURE xxx (pi_record IN table_name%ROWTYPE) as
text VARCHAR2(10000) := NULL;
BEGIN
...
text := 'pi_record.column1 = ' || pi_record.column1 || CHR(13) ||
'pi_record.column2 = ' || pi_record.column2 || CHR(13) ||
...
'pi_record.column170 = ' || pi_record.column170;
logging_procedure (text);
...
END;
Is there any simple way to achieve this in a dynamic way (looping through record fields names and values) without enumerating all of them?
Maybe something like this:
CREATE OR REPLACE PROCEDURE xxx (pi_record IN table_name%ROWTYPE) as
text VARCHAR2(10000) := NULL;
BEGIN
...
LOOP in pi_record.columns
text := text || CHR(13) || pi_record.column.name || ' : ' || pi_record.column.value
END LOOP
logging_procedure (text);
...
END;
Many thanks,
Here's one way to do that. A package spec contains a variable whose type matches the one we'll use in a procedure.
SQL> set serveroutput on
SQL> create or replace package pkg_xxx
2 as
3 dept_rec dept%rowtype;
4 end;
5 /
Package created.
SQL> create or replace procedure xxx (pi_record in dept%rowtype)
2 as
3 text varchar2 (10000) := null;
4 l_str varchar2 (200);
5 l_var varchar2 (200);
6 begin
7 pkg_xxx.dept_rec := pi_record;
8
9 for cur_r in ( select column_name
10 from user_tab_columns
11 where table_name = 'DEPT'
12 order by column_id)
13 loop
14 l_str :=
15 'begin '
16 || ':x := to_char(pkg_xxx.dept_rec.'
17 || cur_r.column_name
18 || '); '
19 || 'end; ';
20
21 execute immediate l_str using out l_var;
22
23 text := text || chr (10) || cur_r.column_name || ' = ' || l_var;
24 end loop;
25
26 dbms_output.put_line (text);
27 end;
28 /
Procedure created.
Now, let's pass something to the procedure and see what happens:
SQL> declare
2 cursor c1
3 is
4 select *
5 from dept
6 where deptno = 10;
7
8 c1r c1%rowtype;
9 begin
10 open c1;
11 fetch c1 into c1r;
12 close c1;
13
14 xxx (c1r);
15 end;
16 /
DEPTNO = 10
DNAME = ACCOUNTING
LOC = NEW YORK
PL/SQL procedure successfully completed.
SQL>
Huh, kind of works (if that's what you asked). Of course, it is just an example, you'll have to modify it if you want to get something really smart (hint: DATE columns).
The only idea I have is to insert the record into a TEMP table:
CREATE OR REPLACE PROCEDURE xxx (pi_record IN TABLE_NAME%ROWTYPE) AS
TEXT VARCHAR2(10000) := NULL;
item VARCHAR2(1000);
TABLE_DOES_NOT_EXIST EXCEPTION;
PRAGMA EXCEPTION_INIT(TABLE_DOES_NOT_EXIST, -942);
BEGIN
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE TABLE_NAME_TMP';
EXCEPTION
WHEN TABLE_DOES_NOT_EXIST then null;
END;
EXECUTE IMMEDIATE 'CREATE GLOBAL TEMPORARY TABLE TABLE_NAME_TMP AS SELECT * FROM TABLE_NAME WHERE ROWNUM = 0';
DELETE FROM TABLE_NAME_TMP;
INSERT INTO TABLE_NAME_TMP VALUES pi_record;
FOR aCol IN (SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS WHERE table_name = 'TABLE_NAME' ORDER BY COLUMN_ID) LOOP
EXECUTE IMMEDIATE 'SELECT '||aCol.COLUMN_NAME||' FROM TABLE_NAME_TMP' INTO item;
TEXT := TEXT || CHR(13) || aCol.COLUMN_NAME || ' : ' || item;
END LOOP;
DBMS_OUTPUT.PUT_LINE ( TEXT );
END;
In case table TABLE_NAME has static attributes then you should skip dynamic DROP TABLE ... and CREATE GLOBAL TEMPORARY TABLE ... and create the TEMP table only once.
everyone!
I got a different approach to get the difference between records dynamically:
You just have to create the global variables on the package header as bellow:
v_NAME_OF_TABLE_new NAME_OF_TABLE%rowtype;
v_NAME_OF_TABLE_old NAME_OF_TABLE%rowtype;
then create the function on your pkg body that return a boolean even if a field is different:
function is_different(p_old NAME_OF_TABLE%rowtype, p_new NAME_OF_TABLE%rowtype)
return boolean
is
cursor cols is
select tb.COLUMN_NAME
from all_tab_columns tb
where tb.OWNER = 'DW'
and tb.TABLE_NAME = 'NAME_OF_TABLE'
order by tb.COLUMN_ID;
l_sql varchar2(4000);
l_new varchar2(4000);
l_old varchar2(4000);
begin
pkg_NAME.v_NAME_OF_TABLE_new := p_new;
pkg_NAME.v_NAME_OF_TABLE_old := p_old;
for reg in cols loop
l_sql := '
begin
:x := pkg_NAME.v_NAME_OF_TABLE_new.'||reg.COLUMN_NAME||';'||'
end;';
execute immediate l_sql using out l_new;
l_sql := '
begin
:x := pkg_NAME.v_NAME_OF_TABLE_old.'||reg.COLUMN_NAME||';'||'
end;';
execute immediate l_sql using out l_old;
--- dbms_output.put_line(l_new||' - '||l_old);
if nvl(l_new,'NULO') <> nvl(l_old,'NULO') then
return true;
end if;
end loop;
return false;
end;
Atention: This can turn your process heavier and slower.
That's all!
Hope this can be helpful!

Dynamic select in Oracle

I want to do something like this:
sql_str := 'select ';
if (user_input = 1) then
sql_str := sql_str || 'a.col1 from tb1 a';
else
sql_str := sql_str || 'a.col1, b.col2, b.col3 from tb1 a, tb2 b';
execute sql_str
I don't have much, not to say any, experience with Oracle's procedures, functions, etc.
I'm having trouble to find out how to create a procedure (or function) in Oracle to perform the above code.
Any help is appreciated. Thank you.
As you are not returning any value we have to go for procedure. Although use case is not clear.
CREATE PROCEDURE dyn_sql_query (user_input IN NUMBER)
IS
sql_str VARCHAR2 (500) := 'SELECT ';
BEGIN
IF (user_input = 1)
THEN sql_str := sql_str || 'a.col1 from tb1 a';
ELSE sql_str := sql_str || 'a.col1, b.col2, b.col3 from tb1 a, tb2 b';
END IF;
EXECUTE IMMEDIATE sql_query;
END;
Here is very basic script for function (notice RETURN) that accepts table name and returns number of rows.
CREATE FUNCTION count_rows (table_name IN VARCHAR2)
RETURN PLS_INTEGER //
IS
sql_query VARCHAR2 (500) := 'SELECT COUNT(*) FROM ' || table_name;
ret_val PLS_INTEGER;
BEGIN
EXECUTE IMMEDIATE sql_query INTO ret_val;
RETURN ret_val;
END;
Using Your Example, Here is One Approach to Dynamic SQL
As others have indicated, there are many examples of dynamic sql on Stack Exchange.
The documentation is very good on this subject. I like the using clause which makes the dynamic sql more extensible.
In practice, the dynamic sql does something: select ... into, a procedural call, dml, dcl.
SCOTT#dev>declare
2 user_input number(1) :=1;
3 sql_str varchar2(1000);
4 begin
5
6 sql_str := 'select ';
7 if (user_input = 1) then
8 -- sql_str := sql_str || 'a.col1 from tb1 a';
9 sql_str := sql_str || '''1'' from dual';
10 dbms_output.put_line(sql_str);
11 else
12 -- sql_str := sql_str || 'a.col1, b.col2, b.col3 from tb1 a, tb2 b';
13 sql_str := sql_str || '''2'' from dual';
14 dbms_output.put_line(sql_str);
15 end if;
16 execute immediate sql_str;
17 end;
18 /
select '1' from dual
PL/SQL procedure successfully completed.
SCOTT#dev>declare
2 user_input number(1) :=2;
3 sql_str varchar2(1000);
4 begin
5
6 sql_str := 'select ';
7 if (user_input = 1) then
8 -- sql_str := sql_str || 'a.col1 from tb1 a';
9 sql_str := sql_str || '''1'' from dual';
10 dbms_output.put_line(sql_str);
11 else
12 -- sql_str := sql_str || 'a.col1, b.col2, b.col3 from tb1 a, tb2 b';
13 sql_str := sql_str || '''2'' from dual';
14 dbms_output.put_line(sql_str);
15 end if;
16 execute immediate sql_str;
17 end;
18 /
select '2' from dual
PL/SQL procedure successfully completed.
With my example as people have commented, a simple select statement usually does not make sense (no one does this in practice).
One can see that my dynamic sql is parsed by looking at v$sql which shows statistics on the shared sql area:
APPS#dev>SELECT
2 sql_id
3 FROM
4 v$sql
5 WHERE
6 1 = 1
7 AND (
8 sql_text = 'select ''1'' from dual'
9 OR
10 sql_text = 'select ''2'' from dual'
11 ) AND
12 parsing_schema_name = 'SCOTT';
SQL_ID
-------------
27q1fj58cnz0k
c9bw73fh2ay8d
addendum based on comments
As Alex cited, the documentation indicates that a select statement without an into clause does not get executed. It is at least parsed and can be seen in the shared sql area, v$sql.
Here is my example with the into clause.
APPS#dev>DECLARE
2 user_input NUMBER(1) := 1;
3 sql_str VARCHAR2(1000);
4 v_val VARCHAR2(1);
5 BEGIN
6 sql_str := 'select ';
7 IF
8 ( user_input = 1 )
9 THEN
10 -- sql_str := sql_str || 'a.col1 from tb1 a';
11 sql_str := sql_str || '''1'' from dual';
12 ELSE
13 -- sql_str := sql_str || 'a.col1,b.col2,b.col3 from tb1 a,tb2 b';
14 sql_str := sql_str || '''2'' from dual';
15 END IF;
16
17 EXECUTE IMMEDIATE sql_str INTO
18 v_val;
19 dbms_output.put_line(sql_str || ' => ' || v_val);
20 END;
21 /
select '1' from dual => 1
PL/SQL procedure successfully completed.
I am not sure if it helps you but you can create a procedure something like below
CREATE OR REPLACE PROCEDURE test_Ali (user_input IN VARCHAR2(2))
IS
sql_str VARCHAR2(1000):= 'select ';
user_input VARCHAR2(2) := '1';
BEGIN
IF user_input = '1' THEN
BEGIN
sql_str := sql_str||'a.col1 from tb1 a';
EXECUTE IMMEDIATE sql_str;
dbms_output.put_line (sql_str) ;
END;
ELSE
BEGIN
sql_str := sql_str||'a.col1, b.col2, b.col3 from tb1 a, tb2 b';
EXECUTE IMMEDIATE sql_str;
dbms_output.put_line (sql_str) ;
END;
END IF;
END;

How to trace abnormal termination in pl sql

I have a pl sql file which process around 7000 records. Based on input it does select insert ,update to different table. Exception handler is written in each query. But my program terminates abnormally without displaying any error message. And this termination happens at different places of code at each time. First time it may process 1200 records, next time it process 1400. Is it related to cache issue? Please provide the input to resolve this issue. I am using sql developer 1.5.4. Is there any way to debug such scenario?
Adding Pl sql file:
Below is my pl sql file and which reads the input from 'marx_resph_bk.txt' as mentioned in file.
=================================================================================
SET SERVEROUTPUT ON;
exec dbms_output.enable(NULL);
declare
v_line varchar2(500);
v_cnt integer;
v_cntp integer:=0;
v_cnth integer:=0;
v_file_date date := to_date('20140201','yyyymmdd');
v_avail_date date := to_date('20131210','yyyymmdd');
v_sent_date date;
v_eff_date date;
v_status char;
ACCEPTED char := 'A';
REJECTED char := 'R';
v_tracking_id kc.kc_marx_transaction.kmt_marx_tsa_sk%type;
v_hicn kc.kc_marx_transaction.kmt_hicn_id%type;
v_c_id kc.kc_marx_transaction.c_id%type;
v_trcs kc.kc_marx_transaction.kmt_tsa_rpy_cd%type;
v_disp_cd kc.kc_marx_transaction.kmt_disp_cd%type;
v_pl_id kc.kc_hcfa_mbr_transaction.pl_id%type;
v_cms_ttc kc.kc_hcfa_mbr_transaction.kcmt_type_code%type;
v_ic_ttc kc.kc_hcfa_mbr_transaction.kcmt_type_code%type;
v_td_id kc.kc_validations.td_id%type;
v_qd_id kc.kc_validations.qd_id%type;
f_verbatim utl_file.file_type;
f_errors utl_file.file_type;
cursor c_Trcs is
select kcmt_reply_code trc
from kc.kc_hcfa_mbr_transaction
where c_id = v_c_id
and pl_id = v_pl_id
and kcmt_file_date = v_file_date
and kcmt_cms_aval_dt = v_avail_date
and kcmt_type_code = v_cms_ttc;
begin
utl_file.fclose(f_verbatim);
utl_file.fclose(f_errors);
f_verbatim := utl_file.fopen ('/net/iRX_downloads2/work/infocare_utl', 'marx_resph_bk.txt', 'r');
f_errors := utl_file.fopen('/net/iRX_downloads2/work/infocare_utl', 'marx_result.txt', 'w');
<<next_hic>>
loop
begin
utl_file.get_line(f_verbatim, v_line);
v_cntp := v_cntp+1;
dbms_output.put_line(' Line CNT: '||v_cntp);
exception
when no_data_found then
dbms_output.put_line(' No Line');
exit;
end;
v_hicn := substr(v_line,1,10);
v_status := substr(v_line,474,1);
v_tracking_id := to_number(substr(v_line,486,15));
begin
dbms_output.put_line(' Selecting marx_transaction');
select c_id, substr(kmt_ctc_id,2,4), kmt_tsa_cd, kmt_eff_dt,
kmt_snt_to_marx_sys_dt, nvl(kmt_disp_cd,'X')
into v_c_id, v_pl_id, v_ic_ttc, v_eff_date, v_sent_date, v_disp_cd
from kc.kc_marx_transaction
where kmt_marx_tsa_sk = v_tracking_id;
if v_disp_cd <> 'X' then
dbms_output.put_line(' Skipping');
goto next_hic;
end if;
exception
when others then
dbms_output.put_line(' Selecting tracking Id');
utl_file.putf(f_errors, 'Select Tracking ID :'||v_tracking_id
||':'||sqlerrm);
rollback;
return;
end;
if v_pl_id = '3909' then
v_pl_id := '3963';
end if;
v_cms_ttc := v_ic_ttc;
v_td_id := null;
v_qd_id := null;
case
when v_ic_ttc = '51' then
v_td_id := '50'; v_qd_id := '85';
when v_ic_ttc = '61' then
v_td_id := '10'; v_qd_id := '20';
when v_ic_ttc = '71' then
v_td_id := '90'; v_qd_id := '140'; v_cms_ttc := '61';
when v_ic_ttc = '73' then
v_td_id := '73'; v_qd_id := '445';
when v_ic_ttc = '75' then
v_td_id := '72'; v_qd_id := '430';
when v_ic_ttc in ('72','76','78','80','81') then
null;
else
utl_file.putf(f_errors, 'Invalid TTC:'||v_ic_ttc||':Tracking ID :'
||v_tracking_id);
dbms_output.put_line(' Invalid TTC:');
goto next_hic;
end case;
if v_status = REJECTED then
begin
delete kc.kc_validations
where c_id = v_c_id
and pl_id = v_pl_id
and td_id = v_td_id
and ec_code like 'C%';
exception
when others then
null;
end;
end if;
v_cnt := 0;
v_trcs := null;
for l_1 in c_Trcs loop
v_trcs := v_trcs||l_1.trc;
v_cnt := v_cnt + 1;
dbms_output.put_line(' Inside Cursor loop');
-- Only need to store validation errors for those TTCs that can be
-- worked through the browse queue screens in the front end
if v_status = REJECTED and v_td_id is not null then
begin
insert into kc.kc_validations
(c_id, pl_id, td_id, qd_id, ec_code, v_column_db_name, v_update_date)
values
(v_c_id, v_pl_id, v_td_id, v_qd_id, 'C'||l_1.trc, ' ', sysdate);
exception
when others then
dbms_output.put_line(' Validation Insert:');
utl_file.putf(f_errors, 'Validation Insert: c_id :'||v_c_id
||': pl_id :'||v_pl_Id||': td_id :'||v_td_id||': '||sqlerrm);
rollback;
return;
end;
if (l_1.trc = '127' or l_1.trc = '169') and v_ic_ttc = '61' then
begin
update kc.kc_customer_coverages_new
set ccv_prj_eff_date = v_eff_date,
ccv_accrete_eff_date = v_sent_date,
ccv_ssa_medd_wth_prem_eff_dt = v_eff_date,
ccv_lis_eff_dt = v_eff_date,
ccv_update_date = sysdate,
ccv_update_userid = user,
cet_type = '4A'
where c_id = v_c_id
and pl_id = v_pl_id;
exception
when others then
dbms_output.put_line(' Error found CCV');
utl_file.putf(f_errors, 'CCV Update:c_id:'||v_c_id||':pl_id:'
||v_pl_id||':eff_dt:'||to_char(v_eff_date,'yyyymmdd')||':'
||'sent_dt:'||to_char(v_sent_date,'yyyymmdd')||':'||sqlerrm);
rollback;
return;
end;
end if;
end if;
-- KC.KC_MARX_TRANSACTION.KMT_TSA_RPY_CD is only large enough to
-- accommodate a string of five TRCs (rarely, if ever, is this needed)
if v_cnt = 5 then
exit;
end if;
end loop;
begin
v_cnth := v_cnth+1;
dbms_output.put_line(' CNT: '||v_cnth);
dbms_output.put_line('v_status: '||v_status||' v_trcs: '||v_trcs||' v_tracking_id: '||v_tracking_id );
dbms_output.put_line(' v_C_ID: '||v_c_id||' v_hicn: '||v_hicn);
update kc.kc_marx_transaction
set kmt_disp_cd = v_status,
kmt_tsa_rpy_cd = v_trcs,
kmt_rsp_pcs_by_marx_sys_dt = sysdate,
last_upd_use_id = user,
last_upd_ts = sysdate,
last_upd_pgm_nm = 'ACCRETION II - ACCR_ACC_REJ_STATUS.SQL'
where kmt_marx_tsa_sk = v_tracking_id;
exception
when others then
dbms_output.put_line(' Error Update Tracking');
utl_file.putf(f_errors, 'Update Tracking ID :'||v_tracking_id
||':'||sqlerrm);
rollback;
return;
end;
end loop;
dbms_output.put_line('TOTAL CNT: '||v_cnth);
utl_file.fclose(f_verbatim);
utl_file.fclose(f_errors);
commit;
end;
/
==============================================================================
And it never reach to a point whereit can display my final dbms_output.put_line for Total CNT.
You exception handler
when others then
dbms_output.put_line(' Selecting tracking Id');
utl_file.putf(f_errors, 'Select Tracking ID :'||v_tracking_id
||':'||sqlerrm);
rollback;
return;
contains error tracking write to file - what about dbms_output.put_line() with the same information ? You could get this as spool file output. Also seems you use loop - end loop; and goto control method - could you use while() looping instead ? It might be more transaparent.
Ald also you have a problem with RETURN statement I guess - because you don't close file handler before return in nested block you don't have information about the error, the file is empty and you don't reach the end of main block:
SQL> declare
2
3 f_errors utl_file.file_type;
4
5 begin
6 utl_file.fclose(f_errors);
7 f_errors := utl_file.fopen('FDC_BTI_DIR', 'test_01.txt', 'w');
8 begin
9
10 raise no_data_found;
11
12 exception
13 when others then
14 dbms_output.put_line(' Selecting tracking Id');
15 utl_file.putf(f_errors, 'Select Tracking ID :'||sqlerrm);
16 rollback;
17 return;
18 end;
19 utl_file.fclose(f_errors);
20 end;
21 /
Selecting tracking Id
SQL> declare
2
3 f_errors utl_file.file_type;
4 buff varchar2(4000);
5
6 begin
7 utl_file.fclose(f_errors);
8 f_errors := utl_file.fopen('FDC_BTI_DIR', 'test_01.txt', 'r');
9 utl_file.get_line(f_errors, buff, 4000);
10 dbms_output.put_line(buff);
11 utl_file.fclose(f_errors);
12 end;
13 /
declare
*
error in line 1:
ORA-01403: data not found
ORA-06512: at "SYS.UTL_FILE", line 106
ORA-06512: at "SYS.UTL_FILE", line 746
ORA-06512: at line 9
SQL> declare
2
3 f_errors utl_file.file_type;
4
5 begin
6 utl_file.fclose(f_errors);
7 f_errors := utl_file.fopen('FDC_BTI_DIR', 'test_01.txt', 'w');
8 begin
9
10 raise too_many_rows;
11
12 exception
13 when others then
14 dbms_output.put_line(' Selecting tracking Id');
15 utl_file.putf(f_errors, 'Select Tracking ID :'||sqlerrm);
16 utl_file.fclose(f_errors);
17 rollback;
18 return;
19 end;
20 utl_file.fclose(f_errors);
21 end;
22 /
Selecting tracking Id
SQL> declare
2
3 f_errors utl_file.file_type;
4 buff varchar2(4000);
5
6 begin
7 utl_file.fclose(f_errors);
8 f_errors := utl_file.fopen('FDC_BTI_DIR', 'test_01.txt', 'r');
9 utl_file.get_line(f_errors, buff, 4000);
10 dbms_output.put_line(buff);
11 utl_file.fclose(f_errors);
12 end;
13 /
Select Tracking ID :ORA-01422: exact fetch returns more than requested number of rows
SQL> declare
2
3 f_errors utl_file.file_type;
4
5 begin
6 utl_file.fclose(f_errors);
7 f_errors := utl_file.fopen('FDC_BTI_DIR', 'test_01.txt', 'w');
8 begin
9
10 raise invalid_number;
11
12 exception
13 when others then
14 dbms_output.put_line(' Selecting tracking Id');
15 utl_file.putf(f_errors, 'Select Tracking ID :'||sqlerrm);
16 rollback;
17 end;
18 utl_file.fclose(f_errors);
19 end;
20 /
Selecting tracking Id
SQL> declare
2
3 f_errors utl_file.file_type;
4 buff varchar2(4000);
5
6 begin
7 utl_file.fclose(f_errors);
8 f_errors := utl_file.fopen('FDC_BTI_DIR', 'test_01.txt', 'r');
9 utl_file.get_line(f_errors, buff, 4000);
10 dbms_output.put_line(buff);
11 utl_file.fclose(f_errors);
12 end;
13 /
Select Tracking ID :ORA-01722: invalid_number

Resources