Procedure with Exception Handling - oracle

Create a PL/SQL Procedure to insert employee details into Employee table. Before inserting, check whether the employee age is eligible or not. Employee age should be 18 or greater. Values are passed as argument to the procedure.
If age valid, insert employee record into table and print the message "Age valid - Record inserted", else print the message "Age invalid - Record not inserted" by raising an exception.
coding:
CREATE OR REPLACE PROCEDURE CHECK_AGE_ELIGIBILITY(
v_id IN EMPLOYEE.EMPID%TYPE,
v_name IN EMPLOYEE.EMPNAME%TYPE,
v_age IN EMPLOYEE.AGE%TYPE)AS
BEGIN
INSERT INTO Employee(EMPID,EMPNAME,AGE)Values(103,'Robert',24);
select age from Employee;
IF AGE >=18
dbms_output.put_line('Age valid -Record inserted');
else
dbms_output.put_line('Age invalid -Record not inserted');
END;
/
EXPECTED OUTPUT:
Age valid -Record inserted

You want to check first, then insert if the check succeds (while your code is doing things the other way around). I also fixed the syntax of your if statement, and changed the insert statement so it uses the procedure arguments instead of hardcoded values. Finally, if you want to raise an error, then use raison_application_error() rather than put_line().
This should do what you want:
create or replace procedure check_age_eligibility(
v_id in employee.empid%type,
v_name in employee.empname%type,
v_age in employee.age%type
)
as
begin
if v_age >=18 then
insert into employee(empid,empname,age)values(v_id, v_name, v_age);
dbms_output.put_line('age valid -record inserted');
else
raise_application_error( -20001, 'age invalid - record not inserted' );
end if;
end;
/
Although this might not be what you were asked to do, please note that you don't need a procedure for this. You can just use a check constraint:
alter table employee add constraint age_above_18 check(age >= 18);
You can then use regular insert statements to feed the table - an error is raised for each row that conflicts with the constraint.
Demo on DB Fiddle

If you want to include the user-defined exception. declare it inside the procedure.
create or replace PROCEDURE CHECK_AGE_ELIGIBILITY(
v_id IN EMPLOYEE.EMPID%TYPE,
v_name IN EMPLOYEE.EMPNAME%TYPE,
v_age IN EMPLOYEE.AGE%TYPE) as
not_of_age exception;
begin
if v_age>=18 then
insert into EMPLOYEE(empid,empname,age) values(v_age,v_name,v_age);
dbms_output.put_line('Age valid - Record inserted');
else
raise not_of_age;
end if;
exception
when not_of_age then
dbms_output.put_line('Age invalid - Record not inserted');
end;
/

Related

Display stored procedure in an anonymous block without getting too many rows error

I have a created stored procedure that has one in parameter and two out parameters.
I want to display the stored procedure in an anonymous PL/SQL block.
The code
CREATE OR REPLACE PROCEDURE task_one
(coun_id IN countries.country_id%TYPE,
coun_name OUT countries.country_name%TYPE,
reg_name OUT regions.region_name%TYPE) IS
BEGIN
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Error! No data found!');
END;
Here you can see my table
When I try to execute the procedure in an anonymous block, I get an error which is too many rows.
In order to block the error, I thought that I can use for loop. However, It didn't work as well. Maybe the way I tried is not right at all.
Here's the anonymous block that tries to display stored procedure
DECLARE
c_name countries.country_name%TYPE;
r_name regions.region_name%TYPE;
BEGIN
FOR c IN (SELECT country_name, region_name INTO c_name, r_name FROM Countries, Regions) LOOP
(task_one('CA', c_name, r_name)
DBMS_OUTPUT.PUT_LINE(c.c_name || ' ' || c.r_name);
END LOOP;
END;
The code of your procedure is incomplete or you did not post everything.
The procedure could look like this:
CREATE OR REPLACE PROCEDURE task_one
(coun_id IN countries.country_id%TYPE,
coun_name OUT countries.country_name%TYPE,
reg_name OUT regions.region_name%TYPE) IS
BEGIN
SELECT country_name, region_name
INTO coun_name, reg_name
FROM countries
JOIN regions ON Countries.region_id = Regions.region_id
WHERE country_id = coun_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Error! No data found!');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('Error! Too many rows!');
coun_name := NULL;
reg_name := NULL;
END;
/
You have to join the two tables via the region_id.
If you also want to get the error "Too many rows", because you might get back several entries for one Country_id (error in the data?), you can do it like in the example.
You can then use the procedure in the anonymous block as follows:
DECLARE
c_name countries.country_name%TYPE;
r_name regions.region_name%TYPE;
BEGIN
task_one('CA', c_name, r_name);
DBMS_OUTPUT.PUT_LINE(c_name || ' ' || r_name);
END;
/

Exception error when creating procedure oracle sql developer

i have been whacking my brain for the past 2 hours can't find a solution to this error. I am creating a simple procedure to find an employee. PL/SQL keeps giving me error. What is the problem ? what am i doing wrong here ?
This is my Procedure:
create or replace PROCEDURE find_employee (employeeNo IN number) as
INVALID_ID exception;
TOO_MANY_ROWS exception;
res number;
BEGIN
dbms_output.enable;
Select count(*) into res from employee where ID=employeeNo;
if (res>1)then -- Checking that the total count of the employee is 1 or not
raise TOO_MANY_ROWS; -- if greater then 1 then it raise TOO_MANY_ROWS error
ELSE IF (NOT EXISTS (Select ID from employee where ID=employeeNo)) -- Checking that the employeeNo user passes exist or not
then
raise INVALID_ID; -- if employeeNo doesnot exit then display invalid id message
ELSE
Select* from Employee where ID=employeeNo; -- else return employee info whose id==employeeNo
END IF;
EXCEPTION
when TOO_MANY_ROWS then
DBMS_OUTPUT.PUT_LINE ('Too many Rows with same employee id');
when INVALID_ID then
DBMS_OUTPUT.PUT_LINE ('Invalid employee id');
END find_employee;
And error is this:
Error(15,1): 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
Error(20,18): PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: end not pragma final instantiable order overriding static member constructor map
Please God Help me :'(
You're missing END IF (line #16). it is easier to spot it if you write formatted code (nested IF should have been indented).
SQL> create or replace PROCEDURE find_employee (employeeNo IN number) as
2 INVALID_ID exception;
3 TOO_MANY_ROWS exception;
4 res number;
5 BEGIN
6 dbms_output.enable;
7 Select count(*) into res from employee where ID=employeeNo;
8 if (res>1)then -- Checking that the total count of the employee is 1 or not
9 raise TOO_MANY_ROWS; -- if greater then 1 then it raise TOO_MANY_ROWS error
10 ELSE IF (NOT EXISTS (Select ID from employee where ID=employeeNo)) -- Checking that the employeeNo user passes exist or not
11 then
12 raise INVALID_ID; -- if employeeNo doesnot exit then display invalid id message
13 ELSE
14 Select* from Employee where ID=employeeNo; -- else return employee info whose id==employeeNo
15 END IF;
16 END IF; --> this is missing
17 EXCEPTION
18 when TOO_MANY_ROWS then
19 DBMS_OUTPUT.PUT_LINE ('Too many Rows with same employee id');
20 when INVALID_ID then
21 DBMS_OUTPUT.PUT_LINE ('Invalid employee id');
22 END find_employee;
As #Dornaut commented, that code probably isn't the best one could produce. Here's another option; see if it helps.
CREATE OR REPLACE PROCEDURE find_employee (employeeNo IN NUMBER)
AS
res NUMBER;
e_row employee%ROWTYPE;
BEGIN
SELECT *
INTO e_row
FROM employee
WHERE id = employeeNo;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line ('Invalid employee ID');
WHEN TOO_MANY_ROWS
THEN
DBMS_OUTPUT.put_line ('Too many rows with same employee ID');
END find_employee;
So: if SELECT returns NO_DATA_FOUND or TOO_MANY_ROWS, it'll be handled. Otherwise, it'll fetch the whole row into a variable.

ORACLE PL/SQL: Calling stored procedure function with multiple parameters (DML query)

New PL/SQL person here. I have a (successfully compiled) PL/SQL function block that manipulates a table in my database by adding a new term to it:
create or replace FUNCTION add_new_term
(TERM_ID_IN IN NUMBER, TERM_IN IN VARCHAR2, IS_METATERM_IN IN NUMBER)
RETURN VARCHAR2
IS
add_term CV_TERMS.TERM_NAME%TYPE; --TERM_NAME is VARCHAR2 type
BEGIN
INSERT INTO CV_TERMS (TERM_ID, TERM_NAME, IS_METATERM)
VALUES (TERM_ID_IN, TERM_IN, IS_METATERM_IN);
dbms_output.put_line('New term successfully added to CV_TERMS table: ' || TERM_IN);
RETURN add_term;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
raise_application_error (-20001, 'You have tried to insert a duplicate term.');
WHEN OTHERS THEN
raise_application_error (-20002, 'An error has occurred inserting a term - '|| SQLCODE ||' -ERROR- '|| SQLERRM);
END add_new_term;
I call this function like calling a stored procedure:
DECLARE
add_term_success cv_terms.term_name%type;
BEGIN
add_term_success := add_new_term(cv_terms_pk.NEXTVAL, 'TESTTT', 0);
END;
SQLDeveloper tells me the procedure was successfully completed, however, the term has not been added to the table. I created the sequence cv_terms_pk independently (it's not in the table CV_TERMS' SQL). Does it need to be there? Am I passing it improperly? Or is something wrong with my add_term declaration? Ideas?
After the DML INSERT you have to commit the transaction.
create or replace FUNCTION add_new_term
(TERM_ID_IN IN NUMBER, TERM_IN IN VARCHAR2, IS_METATERM_IN IN NUMBER)
RETURN VARCHAR2 IS
add_term CV_TERMS.TERM_NAME%TYPE; --TERM_NAME is VARCHAR2 type
BEGIN
INSERT INTO CV_TERMS(TERM_ID, TERM_NAME, IS_METATERM
VALUES (TERM_ID_IN, TERM_IN, IS_METATERM_IN);
COMMIT; ---LINE ADDED ...

Procedure to delete non existing rows oracle

I wrote a procedure in PL/SQL to delete rows from a table,However,if that record does not exist,then throws some error like this: DBMS_OUTPUT.PUT_LINE('No such record'); My procedure is:
CREATE OR REPLACE PROCEDURE del_cn2
(c_cntry_id IN COUNTRIES.COUNTRY_ID%TYPE
)
IS
v_error_code NUMBER;
BEGIN
DELETE from countries
WHERE country_id =c_cntry_id;
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('No such record');
END IF;
EXCEPTION WHEN OTHERS THEN
v_error_code :=SQLCODE;
IF v_error_code =-2292 THEN
RAISE_APPLICATION_ERROR(-20004,'Organization '||TO_CHAR(c_cntry_id)||' site
details defined for it.');
END IF;
END;
/
However,when I execute this procedure and provide a record that does not exist in my table,it gives message "Procedure completed successfully" I am using this to execute:
Execute procedure del_cn2('JJ');
Can someone please suggest?
If you want an exception to be thrown when a value that does not exist in the table is passed in, you would need to actually throw an exception. You shouldn't use dbms_output for any sort of error output. That is a very simplistic debugging tool-- you shouldn't assume that the caller will ever be able to see that output.
My guess is that you want something like
CREATE OR REPLACE PROCEDURE del_cn2
(c_cntry_id IN COUNTRIES.COUNTRY_ID%TYPE
)
IS
BEGIN
DELETE from countries
WHERE country_id =c_cntry_id;
IF SQL%ROWCOUNT = 0
THEN
raise_application_error( -20001, c_cntry_id || ' no such value.' );
END IF;
END;
try to set serverout to ON
example:
create table tst_delete (col1 int);
create procedure p_test_delete as
BEGIN
DELETE FROM tst_delete
WHERE col1 = 1;
IF (SQL%NOTFOUND)
THEN
dbms_output.put_line('No records found');
END IF;
END;
then call the procedure in SqlPlus
SQL> exec p_test_delete;
PL/SQL procedure successfully completed
same issue that you described - no insformation...
next try with output activated
SQL> set serverout on
SQL> exec p_test_delete;
No records found
PL/SQL procedure successfully completed
SQL>

DBMS Pl/SQL -- What would be output ... please explain?

SQL> DESC hostel;
Name Null? Type
------------------------------------ -------- -------------------
HOSTELID NOT NULL VARCHAR2(4)
ROOMSAVAILABLE NUMBER(3)
HOSTELTYPE VARCHAR2(1)
HOSTELFEE NUMBER(6)
SQL> SELECT * FROM hostel;
HOST ROOMSAVAILABLE H HOSTELFEE
------- ---------------------- ---- ---------------------
H1 2 M 2000
H2 3 F 3000
Above is shown a table hostel and values in it.
What would be the output of following pl/sql program?
please explain in detail.
CREATE OR REPLACE PROCEDURE sp_validatehostelid
(p_hostelid IN hostel.hostelid%TYPE,
p_hostelfee OUT hostel.hostelfee%TYPE
)
IS
v_count NUMBER;
v_hostelfee hostel.hostelfee%TYPE;
BEGIN
SELECT COUNT(*) INTO v_count FROM hostel WHERE hostelid=p_hostelid;
IF v_count=0 THEN
RAISE_APPLICATION_ERROR(-20000,'Invalid Hostel id');
ELSE
SELECT hostelfee INTO v_hostelfee FROM hostel WHERE hostelid=p_hostelid;
DBMS_OUTPUT.PUT_LINE('Hostel Fee:'||v_hostelfee);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No data found');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Other Errors in Procedure');
END sp_validatehostelid;
Procedure created.
DECLARE
g_hostelfee hostel.hostelfee%TYPE;
BEGIN
sp_validatehostelid('H5',g_hostelfee);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Other Errors in Block');
END;
"What will be the output? given that there is no row having hostelid =
'H5'"
Assuming you run this in a client with serveroutput enabled the output will be
Other Errors in Procedure
PL/SQL procedure successfully completed.
SQL>
Why?
The first select statement is a count, which cannot hurl a NO_DATA_FOUND exception.
The next line raises a user-defined exception, -20000.
This passes control to the exception handler block. -20000 is not NO_DATA_FOUND so the WHEN OTHERS clause is executed, which displays the message above.
The exception handler does not raise an exception itself, which is very bad practice. So the flow returns to the calling block.
Because no exception was found the calling block thinks the called procedure executed successfully, and so processing terminate cleanly. That's why it is bad practice not re-raise exceptions.
Note that if you run this without enabling serveroutput first the output will be:
PL/SQL procedure successfully completed.
SQL>
CREATE OR REPLACE PROCEDURE sp_validatehostelid
(
p_hostelid IN hostel.hostelid%TYPE,
p_hostelfee OUT hostel.hostelfee%TYPE
)
IS
v_count NUMBER;
v_hostelfee hostel.hostelfee%TYPE;
BEGIN
/* Count rows in 'hostel' table for given ID */
SELECT COUNT(*) INTO v_count FROM hostel WHERE hostelid=p_hostelid;
/* If there is noting in the table */
IF v_count=0 THEN
/* raise exception */
RAISE_APPLICATION_ERROR(-20000,'Invalid Hostel id');
ELSE
/* select fee from the 'hostel' table */
SELECT hostelfee INTO v_hostelfee FROM hostel WHERE hostelid=p_hostelid;
/* print the fee */
DBMS_OUTPUT.PUT_LINE('Hostel Fee:'||v_hostelfee);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No data found');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Other Errors in Procedure');
END sp_validatehostelid;
DECLARE
g_hostelfee hostel.hostelfee%TYPE;
BEGIN
sp_validatehostelid('H5',g_hostelfee);
/*
**Here something should be done with 'g_hostelfee' variable
*/
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Other Errors in Block');
END;
If there is a row with hostelid = 'H5' collect the fee for given ID, print it and pass it out.
NOTE: It will work only for one row per ID. If there is more than one. TO_MANY_VALUES exception will be raised.

Resources