When I tried to update a table which contain 488000 records I got "ORA-21780: Maximum number of object durations exceeded" Error.Please advise me how to resolve this error.
SET SERVEROUTPUT ON SIZE UNLIMITED
DECLARE
v_temp NUMBER :=0;
v_id NUMBER :=0;
BEGIN
FOR fs IN (SELECT * FROM TABLE_A WHERE date < '01-NOV-15')
LOOP
v_temp := (fs.DEPARTURE - fs.ARRIVAL);
v_id :=fs.id;
UPDATE flown_sectors SET DEPARTURE = v_temp
WHERE id = v_id;
END LOOP;
EXCEPTION WHEN OTHERS THEN
dbms_output.put_line('EXCEPTION AT ' ||v_id );
END;
Error report:
ORA-21780: Maximum number of object durations exceeded.
ORA-06512: at "SYS.DBMS_OUTPUT", line 69
ORA-06512: at "SYS.DBMS_OUTPUT", line 82
ORA-06512: at "SYS.DBMS_OUTPUT", line 112
ORA-06512: at line 17
*Cause: This typically happens if there is infinite recursion in the PL/SQL function that is being executed.
*Action: User should alter the recursion condition in order to prevent infinite recursion.
As per the code in the question, if you go on insisting for PLSQL method, try for BULK Update rather than ROW_BY_ROW Update. A very simple scenario mentioned below to suffice your problem. Let me know if this helps.
DECLARE
TYPE lv
IS OBJECT
(EMPNO EMP.EMPNO%TYPE,
SAL EMP.SAL%TYPE
);
TYPE lv_tab IS TABLE OF lv
INDEX BY PLS_INTEGER;
lv_tab_emp lv_tab;
BEGIN
SELECT empno,sal BULK COLLECT INTO lv_tab_emp FROM emp;
FORALL I IN lv_tab_emp.FIRST..lv_tab_emp.LAST
UPDATE EMP_V1
SET SAL = 5100
WHERE EMPNO = lv_tab_emp(i).empno;
END IF;
END;
Related
I've been searching for a while how to resolve this issue and couldn't find anything helpful.
Why this trigger is created with compilation errors?
The warning im getting
Warning: Trigger created with compilation errors.
CREATE OR REPLACE TRIGGER peope_in_dept
AFTER INSERT OR DELETE OR UPDATE on emp
FOR EACH ROW
BEGIN
VARIABLE v NUMBER;
EXECUTE :v := count_people_in_dept(:new.deptno)
IF :v <= 0 or :v >= 10 THEN
raise_application_error(-20000,'Nieodpowiednia liczba pracownikow');
END IF;
END;
/
Syntax errors. Should be
SQL> CREATE OR REPLACE TRIGGER peope_in_dept
2 AFTER INSERT OR DELETE OR UPDATE
3 ON emp
4 FOR EACH ROW
5 DECLARE
6 v NUMBER;
7 BEGIN
8 v := count_people_in_dept (:new.deptno);
9
10 IF v <= 0
11 OR v >= 10
12 THEN
13 raise_application_error (-20000, 'Nieodpowiednia liczba pracownikow');
14 END IF;
15 END;
16 /
Trigger created.
SQL>
However, I suspect it won't work if count_people_in_dept function counts employees in emp table. Why? Because table is mutating:
SQL> UPDATE emp SET comm = 1 WHERE deptno = 10;
UPDATE emp SET comm = 1 WHERE deptno = 10
*
ERROR at line 1:
ORA-04091: table SCOTT.EMP is mutating, trigger/function may not see it
ORA-06512: at "SCOTT.COUNT_PEOPLE_IN_DEPT", line 6
ORA-06512: at "SCOTT.PEOPE_IN_DEPT", line 4
ORA-04088: error during execution of trigger 'SCOTT.PEOPE_IN_DEPT'
SQL>
Now, it depends on what you really are doing in that function. One way out is to set the function to be an autonomous transaction; another one is to use compound trigger; the third option is to use custom type and a package. Or, modify the process altogether (i.e. avoid the trigger).
Why this trigger is created with compilation errors?
Because you are trying to create a SQL/Plus global bind variable inside a PL/SQL procedure and then using EXECUTE rather than just calling the function (and you missed a ; statement terminator).
The correct syntax would be:
FOR EACH ROW
DECLARE
v NUMBER;
BEGIN
v := count_people_in_dept(:new.deptno);
IF v <= 0 or v >= 10 THEN
Then it would compile. However, it still won't work as the table would be mutating as the trigger is running.
Instead, you can use a statement trigger rather than a row trigger:
CREATE OR REPLACE TRIGGER people_in_dept
AFTER INSERT OR DELETE OR UPDATE on emp
DECLARE
v_count PLS_INTEGER;
BEGIN
SELECT 1
INTO v_count
FROM dept d
LEFT OUTER JOIN emp e
ON (e.deptno = d.deptno)
GROUP BY d.deptno
HAVING COUNT(e.deptno) NOT BETWEEN 1 AND 9
FETCH FIRST ROW ONLY;
raise_application_error(-20000,'Nieodpowiednia liczba pracownikow');
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- Do nothing.
NULL;
END;
/
db<>fiddle here
You could also write it as a compound trigger that aggregates the changes in deptno and then only checks the changed values using your function; however, that is a lot more complicated.
I got a problem with trigger whem im trying to insert data to table
CREATE OR REPLACE TRIGGER OGRANICZ
BEFORE INSERT ON BILET
FOR EACH ROW
DECLARE
counter NUMBER(6);
check NUMBER(6);
BEGIN
SELECT id_seans INTO counter FROM seans WHERE id_seans=:NEW.id_seans AND EXTRACT(YEAR FROM data) = 2020;
SELECT COUNT(*) INTO counter FROM BILET B WHERE B.id_seans=:NEW.id_seans;
IF (check = :NEW.id_seans AND counter >=3) THEN
RAISE_APPLICATION_ERROR(-20001, 'too many');
ELSIF(check <> :NEW.id_seans AND counter >=2) THEN
RAISE_APPLICATION_ERROR(-20002, 'too many');
END IF;
END;
I have to set limit for my table that i cant add to many values with the same value for id_seans in bilet table. When im adding too many values for first value of id_seans it works. But if im trying to add any value for other id_seans there is error like this
ORA-01403: no data found ORA-06512: at "SQL_OXRLEFMPXILAXVNAWVBOUVDFO.OGRANICZ", line 6
ORA-06512: at "SYS.DBMS_SQL", line 1721
NO_DATA_FOUND exception might only raise due to the first SELECT statement, while the second one returns an integer starting from zero for any case. So, it's sufficient to handle that exception for the first one in a such a way that
BEGIN
SELECT id_seans
INTO counter
FROM seans
WHERE id_seans=:new.id_seans
AND EXTRACT(YEAR FROM data) = 2020;
EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
END;
what is wrong? everything seems fine. but....
CREATE OR REPLACE TRIGGER salary_change
BEFORE UPDATE
OF emp_salary
ON employee
FOR EACH ROW
WHEN (((NEW.emp_salary-OLD.emp_salary)/OLD.emp_salary)>0.2)
DECLARE
limit NUMBER(7);
BEGIN
limit:=:OLD.emp_salary*1.2;
RAISE_APPLICATION_ERROR (-20000,'rule violated. cannot increase beyond : '|| limit);
END;
I have errors:
ERROR at line 3:
ORA-20000: rule violated. cannot increase beyond : 3360
ORA-06512: at "SYSTEM.SALARY_CHANGE", line 5
ORA-04088: error during execution of trigger 'SYSTEM.SALARY_CHANGE'
The ORA-06512 just tells you what line in your code caused the error. In this case it's line #5 in the trigger, which apparently corresponds to the RAISE_APPLICATION_ERROR call.
So, apparently ((NEW.emp_salary - OLD.emp_salary) / OLD.emp_salary is greater than 0.2. Given that the limit value from the message is 3360, this would mean that OLD.EMP_SALARY was 2800, and NEW.EMP_SALARY was greater than 3360.
Best of luck
USING RAISE_APPLICATION_ERROR ALSO GIVES ERROR ORA-06512 AND POSSIBLY ORA-04088
CREATE OR REPLACE TRIGGER hr.salary_change
before UPDATE
OF salary
ON hr.employees
FOR EACH ROW
WHEN (((NEW.salary-OLD.salary)/OLD.salary)>0.2)
DECLARE
limit NUMBER(8,2);
salary_high exception;
pragma exception_init(salary_high ,-20001);
BEGIN
limit:=:OLD.salary*1.2;
RAISE_APPLICATION_ERROR (-20001,' rule violated. cannot increase beyond :'||to_char(limit));
exception
when salary_high then
:NEW.salary:=:OLD.salary;
dbms_output.put_line(dbms_utility.format_error_stack);
END;
SQL> SET SERVEROUT ON
SQL> select salary from hr.employees where employee_id=198;
SALARY
----------
3900
SQL> update hr.employees set salary=5900 where employee_id=198;
ORA-20001: rule violated. cannot increase beyond :4680
1 row updated.
SQL> select salary from hr.employees where employee_id=198;
SALARY
----------
3900
SQL>
I want to copy one column data into another column in a large table containing 10 millions records.
I am using sys refcursor to copy data from one column into another column. It will taking more than 30 min to copy the data. I am using ORACLE 11gR2.
Is there any others alternative to do the same. Below is the scripts
CREATE OR REPLACE PROCEDURE tblCursor(org_mig OUT SYS_REFCURSOR)
IS
BEGIN
OPEN org_mig FOR
select id from tbl;
END;
/
DECLARE
org_mig SYS_REFCURSOR;
t_id organization.id%TYPE;
loop_var number(10);
commit_interval number(10);
BEGIN
loop_var :=1;
commit_interval:=10000;
tblCursor(org_mig);
LOOP
FETCH org_mig INTO t_id;
EXIT WHEN org_mig%NOTFOUND;
update tbl set col1=col2 where id=t_id;
IF mod(loop_var,commit_interval)=0 THEN
Commit;
End if;
loop_var :=loop_var+1;
END LOOP;
Commit;
CLOSE org_mig;
END;
/
You're doing this for every row in tbl, right? If so, you should just do this:
update tbl
set col1 = col2
/
Updating ten million rows will take some time, but a set operation will be way faster than the Row By Agonizing Row approach you've implemented. Plus, batching up your commits like that is bad practice. Not only does it slow things down, that approach can lead to ORA-01555: Snapshot too old exceptions. Find out more.
Still it has been taken long time to update.
I am trying with different one but getting error.
-----------------------------------
Error starting at line : 43 in command -
SELECT *
FROM TABLE(test_parallel_update(CURSOR(SELECT * FROM organization)))
Error report -
SQL Error: ORA-12801: error signaled in parallel query server P003
ORA-00932: inconsistent datatypes: expected - got -
ORA-06512: at "QA249.TEST_PARALLEL_UPDATE", line 21
12801. 00000 - "error signaled in parallel query server %s"
*Cause: A parallel query server reached an exception condition.
*Action: Check the following error message for the cause, and consult
your error manual for the appropriate action.
*Comment: This error can be turned off with event 10397, in which
case the server's actual error is signaled instead.
---------------------------
Here is the script:
CREATE OR REPLACE TYPE test_num_arr AS TABLE OF NUMBER;
CREATE OR REPLACE FUNCTION test_parallel_update (
test_cur IN SYS_REFCURSOR
)
RETURN test_num_arr
PARALLEL_ENABLE (PARTITION test_cur BY ANY)
PIPELINED
IS
PRAGMA AUTONOMOUS_TRANSACTION;
test_rec organization%ROWTYPE;
TYPE num_tab_t IS TABLE OF NUMBER(10,0);
TYPE vc2_tab_t IS TABLE OF number(1,0);
id NUM_TAB_T;
org_type_old NUM_TAB_T;
IS_DELETED_old VC2_TAB_T;
cnt INTEGER := 0;
BEGIN
LOOP
FETCH test_cur BULK COLLECT INTO id, org_type_old, IS_DELETED_old LIMIT 1000;
EXIT WHEN id.COUNT() = 0;
FORALL i IN id.FIRST .. id.LAST
UPDATE organization
SET org_type = org_type_old(i)
, IS_DELETED = IS_DELETED_old(i)
WHERE id = id(i);
cnt := cnt + id.COUNT;
END LOOP;
CLOSE test_cur;
COMMIT;
PIPE ROW(cnt);
RETURN;
END;
/
show error;
---- To Execute ----
SELECT *
FROM TABLE(test_parallel_update(CURSOR(SELECT * FROM organization)));
Note:
Table
organization
(
id number(10,0),
org_type number(10,0),
org_type_old number(10,0),
IS_DELETED number(1,0),
IS_DELETED_OLD number(1,0)
);
where id is a primary key, Now I want copy org_type_old and IS_DELETED_OLD into org_type and IS_DELETED respectively.
I am trying to create a page process in Oracle APEX 4.1. Specifically, When a button on this page is process submitting the page, I want this PL/SQL query to work. I don't have much of an understanding of PL/SQL and am looking to find out how to figure this issue out.
What I want the query to do:
I would like this page process to loop through each row in the EMPLOYEE table that I have in a database for APEX. For each row, I want to move the username, group and password into their own variables, and then to create an APEX user using the APEX_UTIL_CREATE_USER process. I want this to be done with every employee in the table.
I don't know specifically what is wrong with this PL/SQL, as I have never had to use it before. I would greatly appreciate any help anyone can give me with this. I will show the query and the error message below.
PL/SQL query:
PROCEDURE deploy_employee
(EMP_USERNAME IN EMPLOYEE)
IS
BEGIN
FOR indx IN NVL (EMP_USERNAME.FIRST, 0)
.. NVL (EMP_USERNAME.LAST, -1)
LOOP
emp_user EMPLOYEE.EMP_USERNAME%TYPE;
emp_pass EMPLOYEE.EMP_PASSWORD%TYPE;
emp_group EMPLOYEE.EMP_GROUP%TYPE;
BEGIN
BEGIN
select EMP_USERNAME into emp_user from EMPLOYEE;
select EMP_PASSWORD into emp_pass from EMPLOYEE;
select EMP_GROUP into emp_group FROM EMPLOYEE;
EXCEPTION
WHEN NO_DATA_FOUND THEN
emp_user := NULL;
emp_pass := NULL;
emp_group := NUL;
END;
APEX_UTIL.CREATE_USER(
p_user_name => emp_user,
p_web_password => emp_pass,
p_user_group => emp_gorup,
);
END;
END LOOP;
END deploy_employee;
Error message:
1 error has occurred ORA-06550: line 2, column 1: PLS-00103:
Encountered the symbol "PROCEDURE" 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 The symbol "declare" was
substituted for "PROCEDURE" to continue. ORA-065
The page number is 2.
Once again I would be greatly appreciative of any help I could gain.
There are multiple issues with your procedure.
You are missing the CREATE keyword, and that's the root cause for the compile time error. PLS-00103.
See the documentation for more details on CREATE PROCEDURE statement to create a standalone stored procedure or a call specification.
EMP_USERNAME IN EMPLOYEE
The data type declaration for the IN parameter is incorrect. You need to do it as:
EMP_USERNAME IN EMPLOYEE.EMP_USERNAME%TYPE
The FOR LOOP is syntactically incorrect.
FOR indx IN NVL (EMP_USERNAME.FIRST, 0) .. NVL (EMP_USERNAME.LAST, -1)
You could do it as:
SQL> CREATE OR REPLACE
2 PROCEDURE deploy_emp(
3 i_emp emp.empno%type)
4 IS
5 emp_user VARCHAR2(50);
6 BEGIN
7 FOR indx IN
8 (SELECT ename FROM emp
9 )
10 LOOP
11 BEGIN
12 BEGIN
13 SELECT ename INTO emp_user FROM emp WHERE empno = i_emp;
14 EXCEPTION
15 WHEN NO_DATA_FOUND THEN
16 emp_user := NULL;
17 END;
18 END;
19 END LOOP;
20 dbms_output.put_line(emp_user);
21 END deploy_emp;
22 /
Procedure created.
SQL> sho err
No errors.
Now, let's test it and see:
SQL> set serveroutput on
SQL> EXEC deploy_emp(7369);
SMITH
PL/SQL procedure successfully completed.
SQL>
use CREATE PROCEDURE to create a new stored procedure or EXEC <proc name> to execute it
If you whant do all this in a page process, you don't need to create procedure. Put this code in the source of your page process:
BEGIN
FOR indx IN (
select *
from EMPLOYEE
) LOOP
APEX_UTIL.CREATE_USER(
p_user_name => indx.EMP_USERNAME,
p_web_password => indx.EMP_PASSWORD,
p_user_group => indx.EMP_GROUP,
);
END LOOP;
END;