I tried below code to fetch the 1000 rows and loop through to delete 100 row at a time.
DECLARE
COUNTER INTEGER :=0;
v_delstr varchar2(2000);
v_countstr varchar2(2000);
SchemaName Varchar2(40):='Staging';
TableName Varchar2(100):='History';
BEGIN
LOOP
COUNTER := COUNTER + 1;
DBMS_OUTPUT.PUT_LINE('Counter: ');
v_delstr:= 'Delete FROM ' ||SchemaName ||'.'||TableName|| ' where rownum <= 1000 And startdate>=sysdate-731 and startdate<=sysdate-730';
execute immediate v_delstr;
dbms_output.put_line(v_delstr);
v_countstr:= 'BEGIN
DECLARE CANT INTEGER;
SELECT COUNT(*) INTO CANT FROM ' ||SchemaName ||'.'||TableName|| ' where rownum <= 1000 And startdate>=sysdate-731 and startdate<=sysdate-730;
EXIT WHEN CANT <= 100;
COMMIT;
END;';
execute immediate v_countstr;
dbms_output.put_line(v_countstr);
--dbms_output.put_line(v_delstr);
--dbms_output.put_line(v_countstr);
END LOOP;
END;
DECLARE
COUNTER INTEGER :=0;
v_delstr varchar2(2000);
v_countstr varchar2(2000);
SchemaName Varchar2(40):='Staging';
TableName Varchar2(100):='History';
BEGIN
LOOP
COUNTER := COUNTER + 1;
DBMS_OUTPUT.PUT_LINE('Counter: ');
v_delstr:= 'Delete FROM ' ||SchemaName ||'.'||TableName|| ' where rownum <= 10 And startdate>=sysdate-731 and startdate<=sysdate-730';
execute immediate v_delstr;
dbms_output.put_line(v_delstr);
v_countstr:= 'BEGIN
DECLARE CANT INTEGER;
SELECT COUNT(*) INTO CANT FROM ' ||SchemaName ||'.'||TableName|| ' where rownum <= 10 And startdate>=sysdate-731 and startdate<=sysdate-730;
EXIT WHEN CANT <= 1;
COMMIT;
END;';
execute immediate v_countstr;
dbms_output.put_line(v_countstr);
--dbms_output.put_line(v_delstr);
--dbms_output.put_line(v_countstr);
END LOOP;
END;
Got Error
Error report -
ORA-06550: line 3, column 23:
PLS-00103: Encountered the symbol "SELECT" when expecting one of the following:
begin function pragma procedure subtype type <an identifier>
<a double-quoted delimited-identifier> current cursor delete
exists prior
The symbol "begin" was substituted for "SELECT" to continue.
ORA-06550: line 6, column 18:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
( begin case declare end exception exit for goto if loop mod
null pragma raise return select update while with
<an identifier> <a double-quoted delimited-identifier>
<a bind variable> << continue close current delete fetch lock
insert open rollback savepoint set sql execute commit forall
merge pipe purge
ORA-06512: at line 22
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
I am not sure what's your purpose on the code but try this. it will work most probably.
DECLARE
COUNTER INTEGER :=0;
v_delstr VARCHAR2(2000);
v_countstr VARCHAR2(2000);
SchemaName VARCHAR2(40) :='Staging';
TableName VARCHAR2(100):='History';
BEGIN
FOR COUNTER IN 0..9
LOOP
COUNTER := COUNTER + 1;
DBMS_OUTPUT.PUT_LINE('Counter: ');
v_delstr:= 'Delete FROM ' ||SchemaName ||'.'||TableName|| ' where rownum <= 1000 And startdate>=sysdate-731 and startdate<=sysdate-730';
EXECUTE immediate v_delstr;
dbms_output.put_line(v_delstr);
v_countstr:= 'DECLARE
CANT INTEGER;
BEGIN
SELECT COUNT(*) INTO CANT FROM ' ||SchemaName ||'.'||TableName|| ' where rownum <= 1000 And startdate>=sysdate-731 and startdate<=sysdate-730;
EXIT WHEN CANT <= 100;
COMMIT;
END;';
EXECUTE immediate v_countstr;
dbms_output.put_line(v_countstr);
--dbms_output.put_line(v_delstr);
--dbms_output.put_line(v_countstr);
END LOOP;
END;
Related
i wrote a procedure that deals with writing the contents of the QUERY column of ALL_MVIEWS to a file:
DECLARE
v_out_dir_name VARCHAR2(30) := 'DIR_TEST';
v_out_dir_path VARCHAR2(60);
v_count_object_elab NUMBER := 0;
CURSOR c_mviews IS
SELECT
LOWER(MVIEW_NAME) || '.sql' AS FILE_NAME
, QUERY AS SCRIPT
FROM ALL_MVIEWS
;
v_file UTL_FILE.file_type;
BEGIN
FOR r_mview IN c_mviews LOOP
v_file := UTL_FILE.fopen (v_out_dir_name, r_mview.FILE_NAME, 'w');
UTL_FILE.putf (v_file, r_mview.SCRIPT);
UTL_FILE.fclose (v_file);
v_count_object_elab := v_count_object_elab + 1;
END LOOP;
IF v_count_object_elab = 0
THEN
DBMS_OUTPUT.PUT_LINE('NESSUN FILE ELABORATO');
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERRORE = ' || SQLERRM);
IF UTL_FILE.IS_OPEN (v_file) THEN
UTL_FILE.FCLOSE (v_file);
END IF;
RAISE;
END;
/
But the "FOR r_mview IN c_mviews LOOP" statement generates the following error:
Report error -
ORA-06502: PL/SQL: errore di numero o valore
ORA-06512: a line 35
ORA-06512: a line 16
ORA-06512: a line 16
06502. 00000 - "PL/SQL: numeric or value error%s"
*Cause: An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2).
*Action: Change the data, how it is manipulated, or how it is declared so
that values do not violate constraints.
The error is thrown on a materialized view that has QUERY_LEN = 39000.
How can I solve the problem?
Many thanks in advance.
I don't think you are using UTL_FILE correctly. The putf() procedure is for writing and formatting (using printf() style). Try using just put() instead. I did run your script on my database and it executed fine with putf() and put(), but put() is more appropriate.
Also, beware that QUERY is a LONG. If you have a query over 32k I think you will get the error you are seeing. There are some great write-ups online about how awful LONGs are to work with.
I think easiest thing to do is convert the LONG to CLOB with a CREATE TABLE, read that table and then drop it. Here is a routine to do just that. It will create a copy of all_mviews and convert the query to a CLOB and write that in chunks to a file per view.
DECLARE
v_out_dir_name VARCHAR2(30) := 'MVIEW';
v_count_object_elab NUMBER := 0;
v_cursor SYS_REFCURSOR;
v_file utl_file.file_type;
v_start INTEGER;
v_buffer VARCHAR2(1024);
v_file_name VARCHAR2(1024);
v_query CLOB;
table_or_view_does_not_exist EXCEPTION;
PRAGMA EXCEPTION_INIT(table_or_view_does_not_exist,
-00942);
BEGIN
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE all_mviews_clob';
EXCEPTION
WHEN table_or_view_does_not_exist THEN
NULL;
END;
EXECUTE IMMEDIATE 'CREATE TABLE all_mviews_clob AS SELECT mview_name, to_lob(query) AS query FROM all_mviews';
OPEN v_cursor FOR q'[SELECT lower(mview_name) || '.sql' AS file_name,
query AS script
FROM all_mviews_clob]';
LOOP
FETCH v_cursor
INTO v_file_name,
v_query;
EXIT WHEN v_cursor%NOTFOUND;
v_file := utl_file.fopen(location => v_out_dir_name,
filename => v_file_name,
open_mode => 'w');
v_start := 1;
FOR i IN 1 .. ceil(dbms_lob.getlength(lob_loc => v_query) / 1024)
LOOP
v_buffer := dbms_lob.substr(lob_loc => v_query,
amount => 1024,
offset => v_start);
IF v_buffer IS NOT NULL THEN
utl_file.put(file => v_file,
buffer => v_buffer);
utl_file.fflush(file => v_file);
END IF;
v_start := v_start + 1024;
END LOOP;
utl_file.fclose(v_file);
v_count_object_elab := v_count_object_elab + 1;
END LOOP;
IF v_count_object_elab = 0 THEN
dbms_output.put_line('no mviews');
END IF;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('eror = ' || SQLERRM);
IF utl_file.is_open(v_file) THEN
utl_file.fclose(v_file);
END IF;
RAISE;
END;
/
Scenario:
Write a PL/SQL block that takes a department number from a user and increases the salary of all the employees belonging to the department by 10%. The block should display on the screen how many records are updated.
My Program:
DECLARE
V_TOT_ROWS NUMBER(3);
CURSOR emp_cursor IS
SELECT EMPSAL FROM emp WHERE deptno=&DEPT_NO
FOR UPDATE OF EMPSAL NOWAIT;
BEGIN
FOR emp_record IN emp_cursor
LOOP
UPDATE emp
SET EMPSAL=EMPSAL+emp_record.EMPSAL*0.1
WHERE CURRENT OF emp_cursor;
-- V_TOT_ROWS := SQL%ROWCOUNT;
-- DBMS_OUTPUT.PUT_LINE('TOTAL UPDATED RECORDS: ' || V_TOT_ROWS);
DBMS_OUTPUT.PUT_LINE('Updated ' || SQL%ROWCOUNT || ' salaries.');
END LOOP;
COMMIT;
-- DBMS_OUTPUT.PUT_LINE('Updated ' || SQL%ROWCOUNT || ' salaries.');
END;
It is giving 1 row updated every time the loop is executed but if I keep the dbms_output outside the loop, it gives 0.
Please help.
Thanks,
Please check below Script:
declare V_TOT_ROWS NUMBER(3) :=0;
CURSOR emp_cursor IS
SELECT EMPSAL FROM emp WHERE deptno=&DEPT_NO
FOR UPDATE OF EMPSAL NOWAIT;
begin FOR emp_record IN emp_cursor
LOOP
UPDATE emp
SET EMPSAL=EMPSAL+emp_record.EMPSAL*0.1
WHERE CURRENT OF emp_cursor;
V_TOT_ROWS := V_TOT_ROWS+SQL%ROWCOUNT;
-- DBMS_OUTPUT.PUT_LINE('TOTAL UPDATED RECORDS: ' || V_TOT_ROWS);
-- DBMS_OUTPUT.PUT_LINE('Updated ' || SQL%ROWCOUNT || ' salaries.');
END LOOP;
COMMIT;
DBMS_OUTPUT.PUT_LINE('Updated ' || V_TOT_ROWS || ' salaries.'); end;
Use simple update instead of a cursor + forall.
If you use FORALL ... UPDATE, then only 1 record is updated in each loop cycle, so UPDATE returns SQL%ROWCOUNT always = 1.
DECLARE
V_TOT_ROWS NUMBER(3);
BEGIN
UPDATE emp
SET EMPSAL= EMPSAL+ EMPSAL*0.1
WHERE deptno=&DEPT_NO;
V_TOT_ROWS := SQL%ROWCOUNT;
DBMS_OUTPUT.PUT_LINE('TOTAL UPDATED RECORDS: ' || V_TOT_ROWS);
COMMIT;
END;
/
i have a PROCEDURE like this, whenever i execute the procedure it will give result in cursor according select type:
create or replace PROCEDURE EMAT_PROC_DROPDOWN_SELECTALL(SELECT_TYPE IN VARCHAR2, RESULT_SET OUT SYS_REFCURSOR)
AS
SELECT_TYPE_IN VARCHAR2(100);
TABLE_NAME VARCHAR2(100);
FIELD_NAME VARCHAR2(100);
C_ZONE SYS_REFCURSOR;
C_USER_ID SYS_REFCURSOR;
BEGIN
SELECT_TYPE_IN:=SELECT_TYPE;
IF(SELECT_TYPE_IN ='ZONE') THEN
BEGIN
TABLE_NAME:='MM_ZONEMASTER';
FIELD_NAME:='ZONE_NAME';
OPEN C_ZONE FOR
'SELECT DISTINCT' ||FIELD_NAME|| 'FROM' ||TABLE_NAME||';';
LOOP
FETCH C_ZONE INTO RESULT_SET;
EXIT WHEN C_ZONE%NOTFOUND;
END LOOP;
CLOSE C_ZONE;
END;
ELSIF(SELECT_TYPE_IN ='USER') THEN
BEGIN
TABLE_NAME:='AD_USERMASTER';
FIELD_NAME:='USER_ID';
OPEN C_USER_ID FOR
'SELECT DISTINCT' ||FIELD_NAME|| 'FROM' ||TABLE_NAME||';';
LOOP
FETCH C_USER_ID INTO RESULT_SET;
EXIT WHEN C_USER_ID%NOTFOUND;
END LOOP;
CLOSE C_ZONE;
END;
END IF;
END;
but the returns the error ***ORA-00972: identifier is too long
ORA-06512: at "EMAT.EMAT_PROC_DROPDOWN_SELECTALL", line 14
ORA-06512: at line 7
This is the issue: 'SELECT DISTINCT' ||FIELD_NAME|| 'FROM' ||TABLE_NAME||';';
It will see it as SELECT DISTINCTZONE_NAMEFROMMM_ZONEMASTER
The same goes for the other one.
Add spaces and write it as SELECT DISTINCT ' ||FIELD_NAME|| ' FROM ' ||TABLE_NAME||';';
There are missing space in the cursor around the field name and the table name. It reads SELECT DISTINCTZONE_NAMEFROMMM_ZONEMASTER; instead of SELECT DISTINCT ZONE_NAME FROM MM_ZONEMASTER;
Replace that line by this should help :
'SELECT DISTINCT ' ||FIELD_NAME|| ' FROM ' ||TABLE_NAME||';';
Additionally be careful with the use of nested blocks in your IF. I would avoid abusing from it if it's not needed.
Below is a plsql procedure which was written by someone else and I have asked to fix its compilation errors and run it right.
PROCEDURE DropMyTable IS
x number;
TYPE cur_typ IS REF CURSOR;
--type NAME_TBL is table of VARCHAR2(30);
--tab_Table NAME_TBL;
tab_Table VARCHAR2S(30);
stmt VARCHAR2(4096);
stmt2 VARCHAR2(4096);
outerCur cur_typ;
rows NATURAL := 1000;
TABLE_DOES_NOT_EXIST EXCEPTION;
PRAGMA EXCEPTION_INIT(TABLE_DOES_NOT_EXIST, -942);
BEGIN
stmt2 := 'select distinct G_Tab from G_SERVE where G_TYPE=''CAP''';
--Begin
OPEN outerCur FOR stmt2;
LOOP
FETCH outerCur BULK COLLECT INTO
tab_Table LIMIT rows;
EXIT WHEN tab_Table.COUNT = 0;
FOR i IN 1..tab_Table.COUNT LOOP
--------------------------------------------------------------------
-- Drop the tables in G_SERVE.G_TAB
DBMS_OUTPUT.PUT_LINE('*** Drop table: ' || tab_Table(i) || ' ***');
-- BEGIN
--First drop the optable
stmt := 'DROP TABLE ' || tab_Table(i) || '_OPTAB CASCADE CONSTRAINTS';
DBMS_OUTPUT.PUT_LINE(stmt);
EXECUTE IMMEDIATE stmt;
--drop the base table
stmt := 'DROP TABLE ' || tab_Table(i) || ' CASCADE CONSTRAINTS';
DBMS_OUTPUT.PUT_LINE(stmt);
EXECUTE IMMEDIATE stmt;
--drop the Package
stmt := 'DROP PACKAGE ' || tab_Table(i) || '_PKG';
DBMS_OUTPUT.PUT_LINE(stmt);
EXECUTE IMMEDIATE stmt;
EXCEPTION
-- When the table, optab and package doesn't exist,
-- ignore error "ORA-00942: table, optab or package does not exist".
WHEN TABLE_DOES_NOT_EXIST THEN
DBMS_OUTPUT.PUT_LINE('table, optab or package does not exist');
DBMS_OUTPUT.PUT_LINE(CHR(9));
--Re-raises any other errors.
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error!');
RAISE;
END;
END LOOP;
END LOOP;
--END;
END DropMyTable;
First up I have commented out 4th and 5th line of code from begging and changed it to what it looks like now ( 6th line from the top).
Other thing I have commented out 2 BEGIN keywords first commented out "BEGIN" can be seen after
stmt2 := 'select distinct gao_table from GAO_SERVICESIFACE where GAO_TYPE=''CAPABILITY''';
and the second "BEGIN" keyword has been commented out after the following line of code.
DBMS_OUTPUT.PUT_LINE('*** Drop table: ' || tab_Table(i) || ' ***');
Since I suspect that whoever has written this code put unnecessary "BEGIN" keyword (i apologize if I'm wrong as I'm not a plsql expert. But doing all the commenting out thing i got rid of so many errors).
But when I compile the above code I still get following 2 errors.
1)
ORA-06550: line 27, column 7:
PLS-00103: Encountered the symbol "EXCEPTION" when expecting one of the following:
;
( begin case declare end exit for goto if loop mod null
pragma raise return select update while with <an identifier>
<a double-quoted delimited-identifier> <a bind variable> <<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
2)
ORA-06550: line 38, column 9:
PLS-00103: Encountered the symbol "LOOP" when expecting one of the following:
;
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
You have commented out the BEGIN inside the inner loop but not its associated EXCEPTION and END. You need that begin. Also you cannot change an array to a scalar variable while the code still expects an array (references to tab_Table(i) etc.)
Decent indentation of code always makes it easier to follow:
PROCEDURE DropMyTable IS
x number;
TYPE cur_typ IS REF CURSOR;
type NAME_TBL is table of VARCHAR2(30);
tab_Table NAME_TBL;
--tab_Table VARCHAR2S(30);
stmt VARCHAR2(4096);
stmt2 VARCHAR2(4096);
outerCur cur_typ;
rows NATURAL := 1000;
TABLE_DOES_NOT_EXIST EXCEPTION;
PRAGMA EXCEPTION_INIT(TABLE_DOES_NOT_EXIST, -942);
BEGIN
stmt2 := 'select distinct G_Tab from G_SERVE where G_TYPE=''CAP''';
--Begin
OPEN outerCur FOR stmt2;
LOOP
FETCH outerCur BULK COLLECT INTO
tab_Table LIMIT rows;
EXIT WHEN tab_Table.COUNT = 0;
FOR i IN 1..tab_Table.COUNT LOOP
--------------------------------------------------------------------
-- Drop the tables in G_SERVE.G_TAB
DBMS_OUTPUT.PUT_LINE('*** Drop table: ' || tab_Table(i) || ' ***');
BEGIN
--First drop the optable
stmt := 'DROP TABLE ' || tab_Table(i) || '_OPTAB CASCADE CONSTRAINTS';
DBMS_OUTPUT.PUT_LINE(stmt);
EXECUTE IMMEDIATE stmt;
--drop the base table
stmt := 'DROP TABLE ' || tab_Table(i) || ' CASCADE CONSTRAINTS';
DBMS_OUTPUT.PUT_LINE(stmt);
EXECUTE IMMEDIATE stmt;
--drop the Package
stmt := 'DROP PACKAGE ' || tab_Table(i) || '_PKG';
DBMS_OUTPUT.PUT_LINE(stmt);
EXECUTE IMMEDIATE stmt;
EXCEPTION
-- When the table, optab and package doesn't exist,
-- ignore error "ORA-00942: table, optab or package does not exist".
WHEN TABLE_DOES_NOT_EXIST THEN
DBMS_OUTPUT.PUT_LINE('table, optab or package does not exist');
DBMS_OUTPUT.PUT_LINE(CHR(9));
--Re-raises any other errors.
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error!');
RAISE;
END;
END LOOP;
END LOOP;
--END;
END DropMyTable;
I have reinstated that BEGIN and restored the array. I don't know if there is anything else wrong.
How I could print recorset result from the returning cursor, please.
Down below executes fine but I need to see result.
This is block in TOAD, calling package sp AMD_NEEDMSG:
DECLARE
RETURN_RECORDSET CTI_MATRIX.AMD.REF_CURSOR;
BEGIN
CTI_MATRIX.AMD.AMD_NEEDMSG ( '88888888885', RETURN_RECORDSET );
END;
This package spec:
CREATE OR REPLACE PACKAGE CTI_MATRIX.AMD AS
TYPE REF_CURSOR IS REF CURSOR;
PROCEDURE AMD_NEEDMSG (v_CRN IN VARCHAR2, return_recordset OUT REF_CURSOR);
END AMD;
This is package body:
CREATE OR REPLACE PACKAGE BODY CTI_MATRIX.AMD AS
PROCEDURE AMD_NEEDMSG (v_CRN IN VARCHAR2, return_recordset OUT REF_CURSOR) IS
return_flag INTEGER;
row_cnt INTEGER;
number_of_days INTEGER;
var_DATE DATE;
CURSOR ACCNTSEARCH (P_CRN IN VARCHAR2) IS
SELECT DISTINCT COUNT(*) , AMD.MSG_DATE
FROM TBL_AMD_NEEDMSG AMD
WHERE AMD.PHONE_NUMBER = P_CRN AND ROWNUM = 1;
BEGIN
OPEN ACCNTSEARCH(v_CRN);
FETCH ACCNTSEARCH INTO row_cnt, var_DATE;
CLOSE ACCNTSEARCH;
IF (row_cnt = 0)
THEN
INSERT INTO TBL_AMD_NEEDMSG (PHONE_NUMBER, MSG_DATE) VALUES (v_CRN , SYSDATE);
return_flag := 1;
ELSE
SELECT SYSDATE-var_DATE INTO number_of_days FROM dual;
IF (number_of_days>7)
THEN
UPDATE TBL_AMD_NEEDMSG SET MSG_DATE = SYSDATE WHERE PHONE_NUMBER = v_CRN;
return_flag := 1;
ELSE
return_flag := 0;
END IF;
END IF;
COMMIT;
OPEN return_recordset FOR
SELECT return_flag AS ReturnFLag FROM DUAL;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END AMD_NEEDMSG;
END AMD;
/
Bottom line is to return to client a value of return_flag in the form of record set.
To return the return_flag, which is int=1 or 0 you need function that returns a single value, not recordset. Below are general recordset examples - hope this helps:
DECLARE
TYPE empcurtyp IS REF CURSOR;
emp_cv empcurtyp;
--
TYPE namelist IS TABLE OF scott.emp.ename%TYPE;
TYPE sallist IS TABLE OF scott.emp.sal%TYPE;
names namelist;
sals sallist;
BEGIN
OPEN emp_cv FOR
SELECT ename, sal FROM scott.emp
WHERE job = 'MANAGER' ORDER BY sal DESC;
--
FETCH emp_cv BULK COLLECT INTO names, sals;
CLOSE emp_cv;
-- loop through the names and sals collections
FOR i IN names.FIRST .. names.LAST LOOP
DBMS_OUTPUT.PUT_LINE
('Name = ' || names(i) || ', salary = ' || sals(i));
END LOOP;
END;
/
-- SYS_REFCURSOR example --
DECLARE
p_rc_type SYS_REFCURSOR;
emp_rec scott.emp%ROWTYPE;
--
PROCEDURE p_Emp_Info (p_cur_var OUT SYS_REFCURSOR)
IS
BEGIN
OPEN p_cur_var FOR
SELECT ename, job FROM scott.emp WHERE job = 'MANAGER';
LOOP
FETCH p_cur_var INTO emp_rec.ename, emp_rec.job;
EXIT WHEN p_cur_var%NOTFOUND;
dbms_output.put_line(emp_rec.ename ||' '|| emp_rec.job);
END LOOP;
CLOSE p_cur_var;
END p_Emp_Info;
--
BEGIN
p_Emp_Info(p_rc_type);
END;
/