Lv_Line:= Clave ||' '||ValorSeguridad;
UTL_FILE.put(Lf_Archivo, Lv_Line);
The last Line makes me a line break and I need not to make the line break and the UTL_FILE library makes me the line break either with Put or PutLine.
I need the file to look like this:
Currently it looks like this:
That's expected; there's always an empty line at the end of file if you use text mode. But, if you use byte mode, then the line is gone.
This is something like you currently have, I presume:
SQL> declare
2 l_file utl_file.file_type;
3 l_dir varchar2 (100) := 'EXT_DIR';
4 l_filename varchar2 (100) := 'text.txt';
5 l_line varchar2 (100);
6 begin
7 l_line := 'Test text';
8 l_file := utl_file.fopen (l_dir, l_filename, 'W');
9 utl_file.put(l_file, l_line);
10 utl_file.fclose (l_file);
11 exception
12 when others then
13 utl_file.fclose(l_file);
14 raise;
15 end;
16 /
PL/SQL procedure successfully completed.
SQL> $type text.txt
Test text
--> empty line here
SQL>
Do it this way (see comments which mark the difference):
SQL> declare
2 l_file utl_file.file_type;
3 l_dir varchar2 (100) := 'EXT_DIR';
4 l_filename varchar2 (100) := 'text.txt';
5 l_line varchar2 (100);
6 begin
7 l_line := 'Test text';
8 l_file := utl_file.fopen (l_dir, l_filename, 'WB'); --> this
9 utl_file.put_raw (l_file, utl_raw. cast_to_raw (l_line)); --> this
10 utl_file.fclose (l_file);
11 exception
12 when others then
13 utl_file.fclose(l_file);
14 raise;
15 end;
16 /
PL/SQL procedure successfully completed.
SQL> $type text.txt
Test text
SQL> --> no more empty line
Related
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>
I have the problem that when I create the text file it only saves the first 32768 bytes but the file is larger and the rest of the information does not appear in the file.
This is the code in plsql that I am using, I think I am missing something so that the rest of the information is saved in the file.
The generated file
create table tab1 (
col1 clob
);
CREATE OR REPLACE DIRECTORY DOCUMENTS AS '/process/files';
SET SERVEROUTPUT ON
DECLARE
l_file UTL_FILE.FILE_TYPE;
l_clob CLOB;
l_buffer VARCHAR2(32767);
l_amount BINARY_INTEGER := 32767;
l_pos INTEGER := 1;
BEGIN
SELECT col1
INTO l_clob
FROM tab1
WHERE rownum = 1;
l_file := UTL_FILE.fopen('DOCUMENTS', 'Sample2.txt', 'w', 32767);
LOOP
DBMS_LOB.read (l_clob, l_amount, l_pos, l_buffer);
UTL_FILE.put(l_file, l_buffer);
l_pos := l_pos + l_amount;
END LOOP;
UTL_FILE.fclose(l_file);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line(SQLERRM);
UTL_FILE.fclose(l_file);
END;
/
Since writing the clob to a file is a good "generic" sort of routine, I would write it as such
create or replace procedure clob_to_file( p_dir in varchar2,
p_file in varchar2,
p_clob in clob )
as
l_output utl_file.file_type;
l_amt number default 32000;
l_offset number default 1;
l_length number default
nvl(dbms_lob.getlength(p_clob),0);
BEGIN
l_output := utl_file.fopen(p_dir, p_file, 'w', 32760);
while ( l_offset < l_length )
loop
utl_file.put(l_output, dbms_lob.substr(p_clob,l_amt,l_offset) );
utl_file.fflush(l_output);
l_offset := l_offset + l_amt;
end loop; utl_file.new_line(l_output);
utl_file.fclose(l_output);
end;
/
create table test_tab ( col_id number, col_text clob );
declare
l_col_text clob;
begin
for i in 1..5 loop
insert into test_tab values
( i, empty_clob() )
returning col_text into l_col_text;
for i in 1 .. 10 loop
dbms_lob.writeappend( l_col_text, 30001,
rpad('*',30000,'*') || chr(10) );
end loop;
end loop;
end;
/
create or replace procedure dump_table_to_file
(p_dir in varchar2,
p_file_extn in varchar2 default '.txt',
p_col_id in number default null)
is
BEGIN
for x in ( select *
from test_tab
where col_id = nvl(p_col_id,col_id) )
loop
clob_to_file( p_dir,
x.col_id || p_file_extn,
x.col_text );
end loop;
END;
/
exec dump_table_to_file( '/tmp' );
ls -l /tmp/?.txt
-rw-r--r-- 1 oracle 300011 May 17 14:32 /tmp/1.txt
-rw-r--r-- 1 oracle 300011 May 17 14:32 /tmp/2.txt
-rw-r--r-- 1 oracle 300011 May 17 14:32 /tmp/3.txt
-rw-r--r-- 1 oracle 300011 May 17 14:32 /tmp/4.txt
-rw-r--r-- 1 oracle 300011 May 17 14:32 /tmp/5.txt
DBMS_LOB.GETLENGTH(COL_TEXT)
----------------------------
300010
300010
300010
300010
300010
Which is exactly what we expected. You'll get an exception on the fclose if your text does not have a newline every 32k.
I was finally able to generate the full text file
I was missing the function UTL_FILE.fflush
SET SERVEROUTPUT ON
DECLARE
l_file UTL_FILE.FILE_TYPE;
l_clob CLOB;
l_buffer VARCHAR2(32767);
l_amount BINARY_INTEGER := 32767;
l_max_size BINARY_INTEGER := 32767;
l_pos INTEGER := 1;
BEGIN
SELECT col1
INTO l_clob
FROM tab1
WHERE rownum = 1;
l_amount := l_max_size;
l_file := UTL_FILE.fopen('DOCUMENTS', 'Sample2.txt', 'w', 32767);
LOOP
DBMS_LOB.read (l_clob, l_amount, l_pos, l_buffer);
UTL_FILE.put(l_file, l_buffer);
UTL_FILE.fflush(l_file);
l_pos := l_pos + l_amount;
EXIT WHEN l_amount < l_max_size;
END LOOP;
UTL_FILE.fclose(l_file);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line(SQLERRM);
UTL_FILE.fclose(l_file);
END;
/
-rw-rw-rw-+ 1 oracle asmadmin 38105 May 18 00:45 Sample2.txt
My end goal is to query a database, check if v$pdb's exists and then if it does, query it. If it does not, move on and do something else. Basically I want a script that works with 11g and later versions too. I'm falling at the first fence really. I simply want this to output to screen. All it outputs though is "v_str".
SET FEEDBACK OFF;
SET SERVEROUTPUT ON;
declare
v_str varchar2(200);
v_str1 varchar2(200);
begin
v_str := 'select dbid, con_id, name into v_str1 from v$pdbs';
v_str1 := q'!begin dbms_output.put_line('v_str'); end;!';
Execute immediate v_str;
begin dbms_output.put_line(v_str1);
end;
/
Can anyone help me to get the output to prompt to screen...? Thanks!
A little conditional compilation should help out here
SQL> declare
2 has_container varchar2(1);
3 in_container varchar2(1);
4 begin
5 $IF DBMS_DB_VERSION.VER_LE_11_2
6 $THEN
7 has_container := 'N';
8 in_container := 'N';
9 $ELSE
10 has_container := case when to_number(sys_context('USERENV','CON_ID')) = 0 then 'N' else 'Y' end;
11 in_container := case when to_number(sys_context('USERENV','CON_ID')) > 1 then 'Y' else 'N' end;
12 $END
13 dbms_output.put_line('has_container='||has_container);
14 dbms_output.put_line('in_container='||in_container);
15
16 end;
17 /
has_container=Y
in_container=N
In this code
has_container = is the database multitenant (Y/N)
is_container = if the database IS multitenant, am I currently in the root or a pluggable
Then if you want a list, you can use a cursor loop
SQL> declare
2 has_container varchar2(1);
3 in_container varchar2(1);
4 begin
5 $IF DBMS_DB_VERSION.VER_LE_11_2
6 $THEN
7 has_container := 'N';
8 in_container := 'N';
9 $ELSE
10 has_container := case when to_number(sys_context('USERENV','CON_ID')) = 0 then 'N' else 'Y' end;
11 in_container := case when to_number(sys_context('USERENV','CON_ID')) > 1 then 'Y' else 'N' end;
12 if has_container = 'Y' and in_container = 'N' then
13 for i in ( select name from v$pdbs )
14 loop
15 dbms_output.put_line(i.name);
16 end loop;
17 end if;
18 $END
19 dbms_output.put_line('has_container='||has_container);
20 dbms_output.put_line('in_container='||in_container);
21
22 end;
23 /
PDB$SEED
PDB1
PDB2
has_container=Y
in_container=N
SQL>
Morning All, Hopefully someone can help. I'm an MSSQL specialist and have very little experience of Oracle PL/SQL. I've been asked to write an Oracle Stored Procedure which gets specific fields from the latest Monthly audit table. This is what I've come up with but it doesn't seem to run or output anywhere.
Can someone help?
CREATE OR REPLACE PROCEDURE GetLatestMonthAuditTable
AS
BEGIN
DECLARE
v_lastmonth date := interval '-1' month +systimestamp;
v_year varchar2(4) := extract(year from v_lastmonth);
v_month varchar2(2) := extract(month from v_lastmonth);
v_day varchar2(2) := extract(day from LAST_DAY(v_lastMonth));
v_sql varchar2(256) := 'SELECT ACT_CODE, CHANGE_BY, CHANGE_DATE FROM AUDIT_' || v_year || v_month || v_day;
BEGIN
EXECUTE IMMEDIATE v_sql;
END;
END;
You didn't actually run it - you just created a procedure.
Could've been like this:
Sample table:
SQL> CREATE TABLE AUDIT_20211031
2 AS
3 SELECT 1 act_code, 'Littlefoot' change_by, SYSDATE change_date FROM DUAL;
Table created.
Procedure (it is a good habit to display statement you'll run using dbms_output.put_line; once you make sure it is OK, remove that line):
SQL> CREATE OR REPLACE PROCEDURE GetLatestMonthAuditTable
2 AS
3 v_lastmonth DATE := INTERVAL '-1' MONTH + SYSTIMESTAMP;
4 v_year VARCHAR2 (4) := EXTRACT (YEAR FROM v_lastmonth);
5 v_month VARCHAR2 (2) := EXTRACT (MONTH FROM v_lastmonth);
6 v_day VARCHAR2 (2) := EXTRACT (DAY FROM LAST_DAY (v_lastMonth));
7 v_sql VARCHAR2 (200);
8 BEGIN
9 v_sql :=
10 'SELECT ACT_CODE, CHANGE_BY, CHANGE_DATE FROM AUDIT_'
11 || v_year
12 || v_month
13 || v_day;
14
15 DBMS_OUTPUT.put_line (v_sql);
16
17 EXECUTE IMMEDIATE v_sql;
18 END;
19 /
Procedure created.
Testing:
SQL> SET SERVEROUTPUT ON
SQL>
SQL> BEGIN
2 GetLatestMonthAuditTable;
3 END;
4 /
SELECT ACT_CODE, CHANGE_BY, CHANGE_DATE FROM AUDIT_20211031
PL/SQL procedure successfully completed.
SQL>
Now, your procedure doesn't do anything - it runs that select, but it isn't displayed anywhere on the screen.
If it were a function instead, you could return ref cursor and see something. For example:
SQL> CREATE OR REPLACE FUNCTION GetLatestMonthAuditTable
2 RETURN SYS_REFCURSOR
3 AS
4 v_lastmonth DATE := INTERVAL '-1' MONTH + SYSTIMESTAMP;
5 v_year VARCHAR2 (4) := EXTRACT (YEAR FROM v_lastmonth);
6 v_month VARCHAR2 (2) := EXTRACT (MONTH FROM v_lastmonth);
7 v_day VARCHAR2 (2) := EXTRACT (DAY FROM LAST_DAY (v_lastMonth));
8 v_sql VARCHAR2 (200);
9 rc SYS_REFCURSOR;
10 BEGIN
11 v_sql :=
12 'SELECT ACT_CODE, CHANGE_BY, CHANGE_DATE FROM AUDIT_'
13 || v_year
14 || v_month
15 || v_day;
16
17 OPEN rc FOR v_sql;
18
19 RETURN rc;
20 END;
21 /
Function created.
Testing the function:
SQL> SELECT GetLatestMonthAuditTable FROM DUAL;
GETLATESTMONTHAUDITT
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
ACT_CODE CHANGE_BY CHANGE_DATE
---------- ---------- -------------------
1 Littlefoot 16.11.2021 12:14:18
SQL>
I can't execute this anonymous procedure, when I fetch the cursor c_ev I get an invalid cursor error.
The source code of the anonymous procedure and the stored code are here:
CREATE OR REPLACE
PROCEDURE jorge_ResulPartidosPorJornada (p_cod_jor integer,C_partidos OUT SYS_REFCURSOR, C_EV OUT SYS_REFCURSOR) AS
BEGIN
OPEN C_EV FOR
SELECT P.RESULTADOEV, E.NOMBRE
FROM PARTIDOS P, EQUIPOS E
WHERE P.JORNADA_COD=P_COD_JOR
AND P.CODEQUIPO_VISITANTE=E.COD;
CLOSE C_EV;
END;
declare
C_PARTIDOS SYS_REFCURSOR;
C_EL SYS_REFCURSOR;
R_EV PARTIDOS.RESULTADOEV%TYPE;
N_EV EQUIPOS.NOMBRE%TYPE;
jornada integer;
begin
jornada:= 1;
jorge_ResulPartidosPorJornada(jornada, C_PARTIDOS,C_EV);
FETCH C_EV INTO R_EV,N_EV;
WHILE C_EV%FOUND LOOP
dbms_output.put_line(R_EV);
FETCH C_EV INTO R_EV,N_EV;
END LOOP;
END;
Mistake you made was when you closed the cursor in jorge_something procedure.
If you don't (I used Scott's sample tables as I don't have yours), it works:
SQL> create or replace procedure jorge
2 (p_cod_jor in integer,
3 c_partidos out sys_refcursor,
4 c_ev out sys_refcursor
5 )
6 as
7 begin
8 open c_ev for --> don't close it!
9 select empno, ename from emp where deptno = 10;
10 end;
11 /
Procedure created.
SQL> declare
2 c_partidos sys_refcursor;
3 c_el sys_refcursor;
4 r_ev emp.empno%type;
5 n_ev emp.ename%type;
6 jornada integer;
7 begin
8 jornada := 1;
9 jorge (jornada, c_partidos, c_el);
10
11 loop
12 fetch c_el into r_ev,n_ev;
13 exit when c_el%notfound;
14 dbms_output.put_line(r_ev ||' '|| n_ev);
15 end loop;
16 end;
17 /
7782 CLARK
7839 KING
7934 MILLER
PL/SQL procedure successfully completed.
SQL>
If you do close it, it won't work:
SQL> create or replace procedure jorge
2 (p_cod_jor in integer,
3 c_partidos out sys_refcursor,
4 c_ev out sys_refcursor
5 )
6 as
7 begin
8 open c_ev for
9 select empno, ename from emp where deptno = 10;
10 close c_ev;
11 end;
12 /
Procedure created.
SQL> declare
2 c_partidos sys_refcursor;
3 c_el sys_refcursor;
4 r_ev emp.empno%type;
5 n_ev emp.ename%type;
6 jornada integer;
7 begin
8 jornada := 1;
9 jorge (jornada, c_partidos, c_el);
10
11 loop
12 fetch c_el into r_ev,n_ev;
13 exit when c_el%notfound;
14 dbms_output.put_line(r_ev ||' '|| n_ev);
15 end loop;
16 end;
17 /
declare
*
ERROR at line 1:
ORA-01001: invalid cursor
ORA-06512: at line 12
SQL>
By the way, your code won't work anyway. You declared C_EL and used C_EV
C_EL SYS_REFCURSOR;
jorge_ResulPartidosPorJornada(jornada, C_PARTIDOS, C_EV);
^^^^
should be C_EL
but that's probably just a typo.