PLSQL PROCEDURE. I AM NEW TO TO PLSQL - plsql

Create a procedure ADD_DEPT. This procedure will take 3 IN arguments DEPTNO,DNAME,LOC. Insert these values into the DEPT table. Handle the exception if the user tries to insert a duplicate row using User Defined Exception Handler.

First and foremost Stack Overflow is not a place, where we solve your homework. We help you through your problems. Which is by you showing us your current progress, issue/current output and desired outcome/desired output.
But I'll sympathize with you, knowing I was there once too.
CREATE PROCEDURE ADD_DEPT (
P_DEPTNO IN NUMBER,
P_DNAME IN VARCHAR2,
P_LOC IN VARCHAR2
) AS
BEGIN
INSERT INTO DEPT(DEPTNO, DNAME, LOC)
VALUES (P_DEPTNO, P_DNAME, P_LOC);
EXCEPTION WHEN dup_val_on_index THEN
-- Handle your code here
END;
If you want to go the easy route next time, you can simply do that with SQL Developer:
Browse your tables, right click, then click on Generate table API.
Then to handle the exception, right before the END; statement insert the following: EXCEPTION WHEN dup_val_on_index THEN --your code here

Related

How to correctly make a procedure in Pl/SQL in which I create a TABLE and use a CURSOR

The assignment I am trying to do is
"Create a procedure that places the names of all presidents who were born in one specific
state, in a temporary table. Display the contents of this table."
The procedure complies but when I try to invoke it, it gives me:
00000 - "table or view does not exist"
Error(8,5): PLS-00103: Encountered the symbol "CREATE" when expecting one of the following: begin function pragma procedure subtype type current cursor delete exists prior
I have been stuck for a while now. Does anybody know what I am doing wrong?
My code so far is:
CREATE OR REPLACE PROCEDURE stateofpresident(p_state president.state_born%TYPE)
AS
CURSOR c_state IS
SELECT *
FROM president;
BEGIN
execute immediate 'CREATE TABLE presidentFromState;
(
president_name VARCHAR2
)';
FOR r_state IN c_state LOOP
IF(p_state = r_state.state_born) THEN
execute immediate 'INSERT INTO presidentFromState VALUES(r_state.pres_name)';
commit;
END IF;
END LOOP;
execute immediate 'DROP TABLE presidentFromState';
END stateofpresident;
/
SET SERVEROUT ON
BEGIN
stateofpresident('VIRGINIA');
END;
/
SELECT *
FROM presidentFromState;
The immediate cause of your error is the semi-colon (;) at "presidentFromState;" At run fhat terminates the statement and the SQL interpreter at that point does not know what is want, the create syntax is invalid. The statement compiles because at compile time it is a properly formatted string. That is why dynamic SQL should be avoid if at all possible. Your script also has an additional error. Your last select will fail as the table presidentFromState ws not only created but also dropped in the procedure. Finally, just an FYI, the entire FOR cursor and the cursor itself is entirely unnecessary, the entire operation can be completed is one statement: Look into the structure
Insert into table_name(columns)
Select columns ...
Since this obviously an assignment or tutorial I'll leave the exact for your research.

Mutating table trigger error for one type of insert statement

I'm getting mutating table error for statement insert into employee select 'xyz',200 from dual and scripts executes successfully for insert into employee values ('abc',100);.
Can somebody explain why the statement fails for one type of insert statement? Both scripts insert similar type of data into table
details of script:
--table creation
create table employee (name varchar2(30),salary number);
--trigger creation
create or replace trigger emp_trig
before insert on employee
for each row
begin
delete from employee where name=:new.name;
end;
/
--insert statement 1
insert into employee values ('abc',100);
--result : 1 row inserted
--insert statement 2
insert into employee select 'xyz',200 from dual
--result:
Error report -
ORA-04091: table NMS_CON.EMPLOYEE is mutating, trigger/function may not see it
ORA-06512: at "NMS_CON.EMP_TRIG", line 2
ORA-04088: error during execution of trigger 'NMS_CON.EMP_TRIG'
Inserting a single row will not lead to a mutating table error - how could it, since that row wasn't there before?
But insert-select potentially involves more than one row, so then you get the error.
Generally, you should not have non-query DML operations in your trigger. Too many possible side effects and undesirable consequences.
A better approach is to write a procedure that will do the insert for you, do not give insert privileges on the table directly, only to the package that owns the procedure. Then inside that procedure you can do a delete before your insert, or you can do a merge - or whatever.
All the logic is hidden inside the procedure and by restricting privs on the table, you ensure that the procedure must be called.
Hope that helps!

Do I need to commit inside a subprogram that is called by an autonomous transaction procedure?

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.

Unable to handle the exception properly [duplicate]

This question already has answers here:
How to handle exception and execute remaining statements?
(2 answers)
Closed 8 years ago.
In the below code first insert statement is,
insert into customer_master select max(customerid)+1,customer_name from customer_master
where customer_name not in (select customername from customer_master);
Am getting null value insert error for this. Yes, that is right.
But it is stopping below statements of the block from executing.
insert into customer_account_mapping select customerid,upper(pcd(i)),upper(acd(i)),cost from customer_master where customername=customer_name and concat(upper(pcd(i)),upper(acd(i))) not in (select concat(upper(pcode),upper(acode)) from customer_account_mapping);
insert into user_permissions select distinct user_id,sales_person_name,sales_mgr_name,upper(pcd(i)),upper(acd(i)) from user_permissions where sales_person_name=sales_person and concat(upper(pcd(i)),upper(acd(i))) not in (select concat(upper(pcode),upper(acode)) from user_permissions) and rownum<2 ;
Complete code is given below.
create or replace
procedure dashboard_addtion
(customer_name varchar2,pcd parray,acd aarray,sales_person varchar2,cost number)
IS
begin
insert into customer_master select max(customerid)+1,customer_name from customer_master
where customer_name not in (select customername from customer_master);
for i in 1..acd.count loop
insert into customer_account_mapping select customerid,upper(pcd(i)),upper(acd(i)),cost from customer_master where customername=customer_name and concat(upper(pcd(i)),upper(acd(i))) not in (select concat(upper(pcode),upper(acode)) from customer_account_mapping);
insert into user_permissions select distinct user_id,sales_person_name,sales_mgr_name,upper(pcd(i)),upper(acd(i)) from user_permissions where sales_person_name=sales_person and concat(upper(pcd(i)),upper(acd(i))) not in (select concat(upper(pcode),upper(acode)) from user_permissions) and rownum<2 ;
commit;
end loop;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE (SQLERRM);
end;
Am getting null value insert error for this. Yes, that is right.
But it is stopping below statements of the block from executing.
The exception caused process flow to go to the EXCEPTION handler section. That is the end of the program block. So processing stops after handling the exception. This is standard. So in fact, your have titled your question wrongly, because this is the proper way to handle exceptions. The whole point is to preserve the ACIDity of the transaction. Why would you want to continue processing if the first part of your program fails?
Although, having described this as the proper way I feel I must say that "handling" exceptions by simply using DBMS_OUTPUT is extremely bad practice. That won't work in production code because calling progarm won't know an exception occurred. Your procedure needs to log the error and then re-raise the exception. Anything else is just asking for trouble.

trigger for updating a value

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).

Resources