I want to create a procedure to create user so i Write:
But appear the following error:
01002. 00000 - "fetch out of sequence"
*Cause: This error means that a fetch has been attempted from a cursor
which is no longer valid. Note that a PL/SQL cursor loop
implicitly does fetches, and thus may also cause this error.
There are a number of possible causes for this error, including:
1) Fetching from a cursor after the last row has been retrieved
and the ORA-1403 error returned.
2) If the cursor has been opened with the FOR UPDATE clause,
fetching after a COMMIT has been issued will return the error.
3) Rebinding any placeholders in the SQL statement, then issuing
a fetch before reexecuting the statement.
*Action:
1) Do not issue a fetch statement after the last row has been
retrieved - there are no more rows to fetch.
2) Do not issue a COMMIT inside a fetch loop for a cursor
that has been opened FOR UPDATE.
3) Reexecute the statement after rebinding, then attempt to
fetch again.
CREATE OR REPLACE PROCEDURE CREA_USUARIOS_PR IS
CURSOR EMPLEADOS_LISTA IS SELECT ID,NOMBRE,DNI FROM EMPLEADO FOR UPDATE;
SENTENCIA VARCHAR2(1000);
BEGIN
FOR EMPLEADO_PUNTERO IN EMPLEADOS_LISTA LOOP
SENTENCIA:= 'CREATE USER '||CONCAT(REPLACE(EMPLEADO_PUNTERO.NOMBRE,' ',''),CONCAT(to_char(EMPLEADO_PUNTERO.ID),'MERC'))||' IDENTIFIED BY '||to_char(EMPLEADO_PUNTERO.DNI)||' DEFAULT TABLESPACE TS_MERC QUOTA 10M ON TS_MERC';
EXECUTE IMMEDIATE SENTENCIA;
UPDATE EMPLEADO SET USUARIO = CONCAT(REPLACE(EMPLEADO_PUNTERO.NOMBRE,' ',''),CONCAT(EMPLEADO_PUNTERO.ID,'MERC')) WHERE CURRENT OF EMPLEADOS_LISTA;
END LOOP;
END;
/
Related
I am creating a book tracking database for myself that holds information about my books and allows me to keep track of who is borrowing them. I am trying to create a trigger on my Checkouts table that runs if a record is added or updated that will determine if a checkout data has been entered or if a checkin date has been entered and change the "available" field in my Books table to "Y" or "N".
I have created a trigger called "update_book_availablility" on my Checkouts table but I keep getting this error:
"PLS-00103: Encountered the symbol 'end-of-file' when expecting one of the following: ( begin case declare and exception exit for goto if loop mod null pragma raise return select update while with <<continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge standard pipe purge json_object
Errors: check compiler log"
Here is my trigger code:
CREATE OR REPLACE NONEDITIONABLE TRIGGER "UPDATE_BOOK_AVAILABILITY"
AFTER INSERT OR UPDATE OF ISBN, PersonID, checkout_date, checkin_date
ON Checkouts
FOR EACH ROW
BEGIN
IF :NEW.checkout_date = NULL
THEN
UPDATE Book
SET available = 'N'
WHERE ISBN IN (SELECT :NEW.ISBN FROM Checkouts);
END IF;
END;
Here is an image of my ERD:
ERD
I have been looking into and double checking my trigger syntax, If condition syntax, subquery syntax, and googling this error but have found nothing that has helped. I am new to PL/SQL and would appreciate any help in understanding what I have done wrong or missed.
PLS-00103: Encountered the symbol end-of-file error is SYNTAX ERROR
Copied your trigger and adjusted it to one of my test tables - it works. I removed NONEDITIONABLE and changed trigger table name as well as column names and table/column beeing updated by trigger.
To Do:
Check your syntax again or write the trigger from scratch once more
"...WHERE ISBN IN (SELECT :NEW.ISBN FROM Checkouts)..." selects one fixed value (FOR EACH ROW) :NEW.ISBN of triggering table, better ->> "... WHERE ISBN = :NEW.ISBN ..."
Prety sure that you don't need NONEDITIONABLE trigger for your books tracking app...
Regards...
If I have a procedure that is AUTONOMOUS_TRANSACTION that does an insert and then it calls a procedure with an insert, does the second procedure need a commit, or will the procedure with the AUTONOMOUS_TRANSACTION handle the commit?
The answer is NO. The "second" procedure - invoked by the first - does not have to include a COMMIT statement. When you add this statement to the declaration section of a procedure or function...
PRAGMA AUTONOMOUS_TRANSACTION;
the following rule then applies:
Before the subprogram can be closed and control passed back to the
calling block, any DML changes made within that subprogram must be
committed or rolled back.
If there are any unsaved changes, the PL/SQL engine will raise the ORA-06519 exception, as shown below:
CREATE OR REPLACE FUNCTION nothing RETURN INTEGER
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
UPDATE employees SET last_name = 'abc';
RETURN 1;
END;
/
BEGIN
DBMS_OUTPUT.put_line (nothing);
END;
/
ORA-06519: active autonomous transaction detected and rolled back
ORA-06512: at "STEVEN.NOTHING", line 10
ORA-06512: at line 2
OK, so that's the basic idea. Now let's move on the specific question. What if an autonomous transaction procedure calls another procedure, which does not include the pragma shown above but does execute a DML statement and does not commit? Will we see an ORA-06519 error? The code below shows that we will not.
CREATE TABLE me_and_my_lovelies (name VARCHAR2 (100));
BEGIN
INSERT INTO me_and_my_lovelies VALUES ('Grandpa Steven');
INSERT INTO me_and_my_lovelies VALUES ('Loey');
INSERT INTO me_and_my_lovelies VALUES ('Juna');
COMMIT;
END;
/
CREATE OR REPLACE PROCEDURE not_auton_no_commit
AUTHID DEFINER
IS
BEGIN
UPDATE me_and_my_lovelies
SET name = UPPER (name);
END not_auton_no_commit;
/
CREATE OR REPLACE PROCEDURE auton_commit
AUTHID DEFINER
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
not_auton_no_commit ();
COMMIT;
END auton_commit;
/
BEGIN
auton_commit;
END;
/
SELECT COUNT(*) low_name
FROM me_and_my_lovelies
WHERE name <> UPPER (name)
/
LOW_NAME
--------
0
No error is raised. All rows have been updated. So let's go back to the rule:
Before the subprogram can be closed and control passed back to the calling block, any DML changes made within that subprogram must be committed or rolled back.
You might be thinking: But the UPDATE statement (the "DML change") was not made "within" auton_commit. Yes and no. Yes, the UPDATE statement is not part of the text of auton_commit. But the UPDATE statement was executed within the scope of auton_commit. And that's what counts. Any code executed by auton_commit, either "directly" in its executable section or "indirectly" by invoking another subprogram, is part of the autonomous transaction.
The only point at which the rule is applied is when PL/SQL attempts to close auton_commit and return control to the outer block.
LiveSQL script containing the above code here.
More information about autonomous transactions here.
Note: this Q&A was taken from by blog. Full post here.
I have searched extensively on this and I have found a lot of people asking the question but no answers that included code examples to help me understand.
I'd like to write a transaction (in sql using the command line sqlite3 interface) that performs several update statements, and if any of them fail for any reason, rolls back the transaction. The default behaviour appears to be to roll-back the statement that failed but commit the others.
This tutorial appears to advise that it's sufficient to add begin; and rollback; before and after the statements, but that's not true because I've tried it with deliberate errors and the non-error statements were definitely committed (which I don't want).
This example really confuses me because the two interlocutors seem to give conflicting advice at the end - one says that you need to write error handling (without giving any examples) whereas the other says that no error handling is needed.
My MWE is as follows:
create table if not exists accounts (
id integer primary key not null,
balance decimal not null default 0
);
insert into accounts (id, balance) values (1,200),(2,300);
begin transaction;
update accounts set balance = field1 - 100 where id = 1;
update accounts set balance = field1 + 100 where id = 2;
update accounts set foo = 23; //Deliberate error
commit;
The idea is that none of these changes should be committed.
The sqlite3 command-line shell is intended to be used interactively, so it allows you to continue after an error.
To abort on the first error instead, use the -bail option:
sqlite3 -bail my.db < mwe.sql
If you are executing line by line, then the idea is that you first run these commands:
create table if not exists accounts (
id integer primary key not null,
balance decimal not null default 0
);
insert into accounts (id, balance) values (1,200),(2,300);
begin transaction;
update accounts set balance = field1 - 100 where id = 1;
update accounts set balance = field1 + 100 where id = 2;
update accounts set foo = 23; //Deliberate error
At this point, if you have no errors, you run the commit:
commit;
All the updates should be visible if you open a second connection and query the table.
On another hand if you got an error, instead of committing you rollback:
rollback;
All the updates should be rolled back;
If you are doing it programatically in java you would enclose the updates in a try - catch block, and commit at the end of the try, or rollback inside the catch.
I am currently working on an application using Oracle Apex which is being used as a database to keep a record of cabling.
When components in the database are deleted, a PL/SQL trigger is executed which deletes any associations to the components from another table (PORT) and sets the port references to 0.
The trigger seems to work perfectly for the majority of components I attempt to delete, but presents me with a 'numeric or value error' for others and I am struggling to find out why (as shown below)
The trigger being executed looks like this:
create or replace trigger "COMPONENT_TRIGPORT"
AFTER delete
on "COMPONENT"
for each row
declare
TYPE portType IS TABLE OF PORT%ROWTYPE;
port_arr portType;
begin
DELETE FROM PORT
where PORT.COMPONENT_ID = :old.COMPONENT_ID
RETURNING PORT_ID, PORT_NUMBER, COMPONENT_ID, CONNECTOR_ID, PORT_TYPE
BULK COLLECT INTO port_arr;
begin
FOR i IN port_arr.FIRST .. port_arr.LAST
LOOP
update PORT
set PORT.CONNECTOR_ID = 0
where PORT.CONNECTOR_ID = port_arr(i).CONNECTOR_ID;
END LOOP;
end;
end;
I know that the line giving me the error is
where PORT.COMPONENT_ID = :old.COMPONENT_ID
But I cannot work out why it works fine in some cases but not in others!
Replace
FOR i IN port_arr.FIRST .. port_arr.LAST
with:
FOR i IN 1 .. port_arr.COUNT
If no records are deleted the array will not be initialized and port_arr.FIRST and port_arr.LAST will return null, which will raise the exception ORA-06502: PL/SQL: numeric or value error. COUNT is always safe to use, even on a collection that has not been initialized.
I am a newbie in PLSQL and I would like to create a trigger that checks first if there is a record in a table before making an update.
The code I got so far is:
CREATE OR REPLACE TRIGGER table_bu
BEFORE UPDATE ON employee
FOR EACH ROW
DECLARE
v_employee_id:=employee.employee_ID%TYPE;
BEGIN
SELECT employee_id INTO v_employee_id FROM employee;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR (-20001,'data not found');
END;
How I can create a trigger that checks up if a record exists in the table and if it does not exists does not allow the update.
My table estructure is:
employee_id NUMBER
employee_name VARCHAR(20)
employee_salary NUMBER
...
Thanks
You are on a wrong way. The trigger as it is will throw runtime 'Mutating table' error even after fixing syntax error - you missed semicolon after raise_application_error(also it should take 2 arguments, not one). Correct syntax :
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR (-20001, 'data not found'); -- 1st parameter -error code
Update
As far as I understand the updated version of the question, you want to show error if record doesn't exist. The problem with row level trigger approach is that it won't be executed if nothing is found due to condition in WHERE. The simplest way is to check number of rows affected on client side and raise an error there. Or you can write a procedure that checks sql%rowcount after executing desired update, and then throw an exception if it's 0.
If you prefer to do in a hard way, you can create package variable which of type employee.employee_ID%TYPE, before update statement level trigger that resets variable (say set it to null), after update row level trigger that sets this variable to NEW.employee_ID, and after update statement level trigger that throws an exception if the variable is null. Note: this will properly work for individual updates only.
"How I can create a trigger that checks up if a record exists in the table and if it does not exists does not allow the update."
There is really only one practical way to do this - use a referential constraint (foreign key).