This is my procedure:
create or replace procedure p1(p_deptno in number)
is
cursor c is select * from emp where deptno=p_deptno;
i emp%rowtype;
begin
open c;
loop
fetch c into i;
exit when c%notfound;
dbms_output.put_line(i.ename);
end loop;
exception
when no_data_found then
dbms_output.put_line('Give proper deptno');
end p1;
/
When I run it using SQL*Plus, I get this:
SQL> exec p1(70);
PL/SQL procedure successfully completed.
But deptno 70 is not available. Exception should be raised, but it is not. What am I doing wrong?
Using RAISE_APPLICATION_ERROR Will be more appropriate here if we need to show a user defined error for this particular error message.
CREATE OR REPLACE PROCEDURE p1(
p_deptno IN NUMBER)
IS
i emp%rowtype;
BEGIN
SELECT * INTO i FROM emp WHERE deptno=p_deptno;
EXCEPTION
WHEN no_data_found THEN
RAISE_APPLICATION_ERROR(-20001,'Dept no '||p_deptno||' has no data',TRUE);
END p1;
No data found exception would be raised only if you fire a select (not a cursor). Following is a sample based on your code where this would happen:
create or replace procedure p1(p_deptno in number)
is
i emp%rowtype;
begin
select * into i
from emp where deptno=p_deptno;
exception
when no_data_found then
dbms_output.put_line('Give proper deptno');
end p1;
/
You could raise an exception based on %NOTFOUND as demonstrated by Gavin.
Also,the first fetch from an open cursor, cursor_name%NOTFOUND returns NULL.Thereafter, it returns FALSE if the last fetch returned a row, or TRUE if the last fetch failed to return a row. (https://docs.oracle.com/cd/B12037_01/appdev.101/b10807/13_elems011.htm)
You need to call RAISE (documentation link here)
IF i IS NULL THEN
RAISE no_data_found;
END IF;
Related
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.
We are using FORALL.....SAVE EXCEPTIONS. At the end of the loop, we have this:
FOR i IN 1..SQL%BULK_EXCEPTIONS.COUNT LOOP<BR><BR>
DBMS_OUTPUT.PUT_LINE('ERROR CREATING STAGING TICKER: ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));<BR><BR>
DBMS_OUTPUT.PUT_LINE('INDEX INFO: ' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX);<BR>
END LOOP;
Is there any way for me to get at actual VALUES in that array? Say if a customers email was too long.....for me to actually display the value which caused the error? Rather than just some index number?
Thanks!
You can use the loop variable i to display the content of the exception array in your case. See below an example procedure:
CREATE OR REPLACE PROCEDURE PROC1 (V_EMP_ID DBMS_SQL.NUMBER_TABLE)
IS
lv_error_string VARCHAR2(4000);
BEGIN
FORALL INDX IN V_EMP_ID.FIRST..V_EMP_ID.LAST SAVE EXCEPTIONS
UPDATE EMPLOYEES
---trying to rasie an exception by using a calculation
SET SALARY=SALARY * 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
WHERE ID_E= V_EMP_ID(INDX);
EXCEPTION
WHEN OTHERS
THEN
FOR i IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
---Am printing the value of the exception array.
dbms_output.put_line('exception Raised for record' ||V_EMP_ID(i));
END LOOP;
END;
/
Ouput:
SQL> DECLARE
empid DBMS_SQL.NUMBER_TABLE;
BEGIN
empid (1) := 1;
empid (2) := 9;
PROC1 (empid);
END;
/
exception Raised for record 1
PL/SQL procedure successfully completed.
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>
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;
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.