When I execute the procedure nth would appear except the following message and not showing any output which should not be the case: anonymous block completed
I've tried to set serveroutput on size 50000 but nothing changes.
Here's my PL/SQL procedure not sure if i'm doing it right.
CREATE OR REPLACE PROCEDURE verify AS
empnum NUMBER;
empname VARCHAR2(50);
fail EXCEPTION;
BEGIN
SELECT employee.e#, employee.name INTO empnum, empname
FROM employee
JOIN driver ON driver.e# = employee.e#
JOIN mechanic ON mechanic.e# = driver.e#
WHERE rownum = 1;
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('ok');
RAISE fail;
END verify;
/
I'm trying to achieve the following result in using sql statement:
SELECT employee.e#, employee.name
FROM employee
JOIN driver ON driver.e# = employee.e#
JOIN mechanic ON mechanic.e# = driver.e#
WHERE rownum = 1;
So if there's any similar records it will show the employee name and num. If there's no similar records found it will display a ok message.
add dbms_out_put.put_line(empnum||empname);
before the EXCEPTION.
try it/
You are just selecting the column values into the variables and not displaying them. Use DBMS_OUTPUT.put_line('Empnum: '|| empnum||' Empname: '||empname); just after the Select statement.
Can you please signify the FAIL variable you have used to
Raise Exception. We can do it without using this variable. This
is reference procedure.Plz try and let us know if it works. thanks
CREATE or REPLACE PROCEDURE av_sp_test(salary_var_1 in number)
AS
name_var avrajit.name%type;
salary_var avrajit.salary%type;
fail exception;
BEGIN
SELECT name,salary into name_var,salary_var from avrajit
WHERE salary=salary_var_1;
dbms_output.put_line('name is'||' '||name_var||' '||'salary is'||' '||salary_var);
EXCEPTION WHEN no_data_found THEN
dbms_output.put_line('OK');
END av_sp_test;
--------------------------------------------------
I have taken an input variable just to show diffrenet criterias.
begin
av_sp_test(1000);
end;
---------------------------------------------------
name is Sushil salary is 1000
Statement processed.
0.01 seconds
---------------------------------------------------
begin
av_sp_test(2000);
end;
---------------------------------------------------
OK
Statement processed.
0.00 seconds
Related
I having emp table, in that there is no records. I used those table in SQL and PL/SQL block
SQL> BEGIN
2 FOR i IN (SELECT * FROM emp WHERE 1=2) -- emp table having no data
3 LOOP
4 dbms_output.put_line('Done');
5 END LOOP;
6 EXCEPTION
7 WHEN no_data_found THEN
8 dbms_output.put_line('No such value');
9 END;
10 /
PL/SQL procedure successfully completed. -- it shows completed, instead of handling no_data_found
SQL> SELECT * FROM emp
2 WHERE 1=2;
no rows selected -- but here it show no rows selected
In pl/sql block, instead of handling no_data_found it shows pl/sql successfully completed
But in SQL statement it shows no rows selected.
I want to know what is actually happened in plsql and sql statement?
The code between the LOOP and END LOOP clauses is executed once per row in the cursor. Your cursor returns zero rows so it never gets executed.
The cursor loops gracefully handles the empty result by design, because coming to the end of the result set is expected, even when it is zero rows. So it does not hurls the NO_DATA_FOUND exception.
That's why you see no messages.
On the other hand the SQL statement expects a query to return rows and raises no data found when none are returned. However, you are executing the SQL statement in a client - SQL*Plus in this case - which handles this outcome and displays a message.
If you want your PL/SQL to exhibit the same behaviour, don't use a cursor loop:
declare
l_emp_rec emp%rowtype;
begin
select *
into l_emp_rec
from emp
where 1 = 2; -- emp table having no data
dbms_output.put_line('Done');
exception
when no_data_found then
dbms_output.put_line('No such value');
end;
/
I have a Stored procedure in Oracle for getting and displaying data. But I want to implement one more functionality in it.
What I want, I want to throw an exception and that exception I want to log into an Oracle table
Sample Stored procedure
CREATE OR REPLACE PROCEDURE GET_FCA_GISDATA(
P_GRPNAME IN NVARCHAR2,
TBLDATA_APP OUT SYS_REFCURSOR
) AS
BEGIN
OPEN TBLDATA_APP FOR
SELECT IP.ID,
IP.SAP_ID,
IP.ID_OD_COUNTCHANGE,
IP.ID_OD_CHANGEDDATE,
IP.RRH_COUNTCHANGE,
IP.RRH_CHANGEDDATE,
IP.TENANCY_COUNTCHANGE,
IP.TENANCY_CHANGEDDATE,
ST.STATUS,
IP.RFE1_DATE_BAND,
IP.RFS_DATE_BAND,
IP.CREATED_BY
FROM TBL_IPCOLO_MAST_INFO IP
LEFT JOIN TBL_IPCOLO_STATUS ST
ON IP.FCA_STATUS = ST.ID
WHERE UMS_GRP_TO_NAME = P_GRPNAME
AND ST.ISACTIVE = 1
ORDER BY 12 DESC;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END GET_FCA_GISDATA;
Please suggest how to throw the exception.
How to raise your own exception? Like this:
SQL> set serveroutput on
SQL> create or replace procedure p_test is
2 my_ex exception;
3 begin
4 raise my_ex;
5 exception
6 when my_ex then
7 dbms_output.put_line('My exception');
8 end;
9 /
Procedure created.
SQL> exec p_test
My exception
PL/SQL procedure successfully completed.
SQL>
Instead of displaying it on the screen, you'd store it into some table.
a SQL Select statement like the below one might be added, provided the related synonyms of dynamic performance views' select privileges are granted to your current user :
Select count(1)
Into v_locked
From all_objects o
Join v$locked_object l on o.object_id = l.object_id
Join v$session s on l.session_id = s.sid
Join v$session_wait w on s.sid = w.sid
Where o.object_name = 'TBL_IPCOLO_MAST_INFO'
and s.status = 'ACTIVE'
and lower(w.event) like '%enq%contention%' --> "enq: TX - row lock contention"
before invoking the cursor.
If v_locked variable's value is greater than zero then the related table has a row lock contention. That would be alerted and logged in a simple table if v_locked > 0.
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;
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.
I just want to SELECT values into variables from inside a procedure.
SELECT blah1,blah2 INTO var1_,var2_
FROM ...
Sometimes a large complex query will have no rows sometimes it will have more than one -- both cases lead to exceptions. I would love to replace the exception behavior with implicit behavior similiar to:
No rows = no value change, Multiple rows = use last
I can constrain the result set easily enough for the "multiple rows" case but "no rows" is much more difficult for situations where you can't use an aggregate function in the SELECT.
Is there any special workarounds or suggestions? Looking to avoid significantly rewriting queries or executing twice to get a rowcount before executing SELECT INTO.
Whats wrong with using an exception block?
create or replace
procedure p(v_job VARCHAR2) IS
v_ename VARCHAR2(255);
begin
select ename into v_ename
from (
select ename
from scott.emp
where job = v_job
order by v_ename desc )
where rownum = 1;
DBMS_OUTPUT.PUT_LINE('Found Rows Logic Here -> Found ' || v_ename);
EXCEPTION WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No Rows found logic here');
end;
SQL> begin
p('FOO');
p('CLERK');
end; 2 3 4
5 /
No Rows found logic here
Found Rows Logic Here -> Found SMITH
PL/SQL procedure successfully completed.
SQL>
You could use a for loop. A for loop would do nothing for no rows returned and would be applied to every row returned if there where multiples. You could adjust your select so that it only returns the last row.
begin
for ARow in (select *
from tableA ta
Where ta.value = ???) loop
-- do something to ARow
end loop;
end;