PL/SQL Procedure error with exception - plsql

I have table named "players" like this
Name Country
---------- ------------
Sachin India
Ponting Australia
I have written a PL/SQL Procedure to execute it by giving "name" as parameter.
Here is the code-
CREATE OR REPLACE PROCEDURE NEW_TEST ( player IN players.name%type, place IN players.country%type ) IS
countri players.country%type;
BEGIN
SELECT country into countri from players where name = player;
END;
DECLARE
player players.name%type;
place players.country%type;
CURSOR cu_new0 is
SELECT name, country from players where name=player;
BEGIN
player:='Sachin' ;
FOR pl_all in cu_new0
LOOP
NEW_TEST (player, place);
dbms_output.put_line ('The player ' || player || ' play for ' || pl_all.country);
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('No such player!');
WHEN OTHERS THEN
dbms_output.put_line('Error!');
END;
Now when I am putting player:='Sachin' it is giving output but when I am giving player:= 'Sachin1' is not showing any output and more importantly it is not even going to exception of 'NO_DATA_FoUND'. Can you please help me in this regard. Thanx

If you code a loop, Oracle does not throw an exception if no data is returned (just as it doesn't throw a TOO_MANY_ROWS exception if more than one row is returned).

Your one of the select clause is not handling exception; you are consuming exception in that code.
Your Original Code:
BEGIN
SELECT country into countri from players where name = player;
END;
Modify with below code--
BEGIN
SELECT country into countri from players where name = player;
exception when no_data_found then
raise_application_error(......);
END;

DECLARE
player players.name%type;
place players.country%type;
CURSOR cu_new0 is
SELECT name, country from players where name=player;
type l_cu_new0 is table of cu_new0%rowtype;
v_cu_new0 l_cu_new0;
BEGIN
player:='Sachin' ;
open cu_new0;
fetch cu_new0 bulk collect into v_cu_new0;
close cu_new0;
if v_cu_new0.count = 0 then
raise NO_DATA_FOUND;
end;
FOR i in v_cu_new0.first .. v_cu_new0.last
LOOP
...
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('No such player!');
WHEN OTHERS THEN
dbms_output.put_line('Error!');
END;

There are your cursor is NULL. Because;
Temp code block :
select name
,country
from players
where name = :player;
Run code block :
select name
,country
from players
where name = 'Schin1';
Run code block return NULL and your cursor is have NULL value.
Then your for loop code block is not work.
You can solve this problem such as ;
CURSOR cu_new0 is
SELECT name, country from players;
Hi #Warrior92 for edit,
There are maybe you can try it ;
for pl_all in cu_new0 loop
new_test(player
,place);
if pl_all.name = player then
dbms_output.put_line('The player ' || player || ' play for ' || pl_all.country);
end if;
end loop;

If you really want to use a cursor, the for loop and an exception, you can try the following code:
DECLARE
-- create table type of players
TYPE t_players_tab IS TABLE OF players%ROWTYPE;
-- declare variable / array which will contain the result of cursor's select
l_players_arr t_players_tab := NEW t_players_tab();
CURSOR c_fetch_player IS
SELECT
*
FROM
players
WHERE
name = player;
-- declare exception which is to be caught within the EXCEPTION block
EXCEPTION e_player_not_found;
-- init the exception giving it the sqlcode -20001 (valid numbers for custom exceptions are in range from -20000 to -20999)
PRAGMA EXCEPTION_INIT(e_player_not_found, -20001);
BEGIN
-- fetch the cursor result into the array
OPEN c_fetch_player;
FETCH c_fetch_player BULK COLLECT INTO l_players_arr;
CLOSE c_fetch_player;
-- check if the array contains any results
IF l_players_arr.COUNT > 0 THEN
-- iterate through the rows in the array
FOR idx l_players_arr.FIRST .. l_players_arr.LAST
LOOP
dbms_output.put_line ('The player ' || player || ' play for ' || l_players_arr(idx).country);
END LOOP;
ELSE -- if the array has no rows, raise application arror with the same sqlcode as defined in EXCEPTION_INIT
raise_application_error(-20001,'Player ' || player || 'not found');
END IF;
EXCEPTION
-- catch the exception
WHEN e_player_not_found THEN
dbms_output.put_line(sqlcode || ': ' || sqlerrm);
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_CALL_STACK);
DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_STACK);
DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
END;
/

Related

Can anyone help whey my execption section is not working,

My whole intention to catch exception,WRONG parameter is NOT CATCHING exception.
Here is the code:
CREATE OR REPLACE PROCEDURE list_emp (p_emp_id IN employees.employee_id%TYPE,
p_dept_id IN employees.department_id%TYPE)
IS
CURSOR c1 IS
SELECT *
FROM EMPLOYEES
WHERE EMPLOYEE_ID=p_emp_id
AND DEPARTMENT_ID=p_dept_id;
emp_rec c1%ROWTYPE;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO emp_rec;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(emp_rec.employee_id||' '||emp_rec.first_name||' '||emp_rec.last_name);
END LOOP;
CLOSE c1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No Record Found ');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('No Record Found ');
END;
When the cursor is opened and fetched with the wrong parameter that does not match any row from the corresponding table, the following line
EXIT WHEN c1%NOTFOUND;
cause the plsql procedure to terminate (because there were no rows found). Hence no exception is raised.
If you do want to display some sort of output you can do the following instead
IF c1%FOUND THEN
dbms_output.put_line('Record Found');
ELSE
dbms_output.put_line('Finished/Done');
EXIT;
END IF;
If you want to raise an error after looping through a cursor that returns no rows, then you're going to have to use a counter to work out how many rows have been processed, and then you can do something if no rows have been processed.
Something like:
create or replace procedure list_emp (p_emp_id in employees.employee_id%type,
p_dept_id in employees.department_id%type)
is
cursor c1 is
select employee_id,
first_name,
last_name
from employees
where employee_id = p_emp_id
and department_id = p_dept_id;
v_count number := 0;
begin
for emp_rec in c1
loop
v_count := v_count + 1;
dbms_output.put_line(emp_rec.employee_id||' '||emp_rec.first_name||' '||emp_rec.last_name);
end loop;
if v_count = 0 then
raise no_data_found;
end if;
exception
when no_data_found then
dbms_output.put_line('No Record Found.');
raise;
when others then
dbms_output.put_line('An error occurred: '||sqlerrm);
raise;
end;
/
A few notes:
I converted your cursor loop into a cursor-for-loop; you don't need to worry about declaring the record type and also Oracle handles the opening and closing of the cursor for you.
I added raise; to each of your exception handlers - in general, having when others then null (which is effectively what your original code was doing - no errors are raised to the calling code) is a bad idea. I added the raise to the no_data_found condition as that wasn't doing anything either; typically, if you have an exception condition, you want it to do something to let the calling code know there was a problem (not always, of course; sometimes you don't want the processing to stop if a particular error condition is met).
Your cursor was selecting all columns, but in your procedure, you were only using three of them. I've therefore amended the cursor so that it only pulls back those three columns.
Don't rely on dbms_output in your production code. Code that calls this procedure won't see anything populated in dbms_output, unless it explicitly looks for it - and that's not something I've ever seen in any production code, outside of Database tools (eg. SQL*Plus, Toad, etc). I've left this in your procedure as I've a feeling this is a learning exercise for you, but please don't think that this is in any way acceptable in production code.
You're passing p_emp_id in as a parameter - typically, that's the primary key of the employees table. If that's the case, then there's no need for the cursor for loop at all - you could do it by using select ... into ... instead, like so:
.
create or replace procedure list_emp (p_emp_id in employees.employee_id%type,
p_dept_id in employees.department_id%type)
is
v_emp_id employees.employee_id%type;
v_first_name employees.first_name%type;
v_last_name employees.last_name%type;
begin
select employee_id,
first_name,
last_name
into v_emp_id,
v_first_name,
v_last_name
from employees
where employee_id = p_emp_id
and department_id = p_dept_id;
dbms_output.put_line(emp_rec.employee_id||' '||emp_rec.first_name||' '||emp_rec.last_name);
exception
when no_data_found then
dbms_output.put_line('No Record Found.');
raise;
when others then
dbms_output.put_line('An error occurred: '||sqlerrm);
raise;
end;
/
Alternatively, just pass back a ref cursor:
create or replace procedure list_emp (p_emp_id in employees.employee_id%type,
p_dept_id in employees.department_id%type,
p_ref_cur out sys_refcursor)
is
begin
open p_ref_cur for select employee_id,
first_name,
last_name
from employees
where employee_id = p_emp_id
and department_id = p_dept_id;
-- No need for an exception handler here since you're not storing the error details anyway.
-- By not having an error handler, any error will automatically be raised up to the calling code
-- and it will have the correct error stack trace info (e.g. the line number the error occurred,
-- rather than the line the error was reraised from
end;
/
And to run the ref cursor in SQL*Plus (or as a script in Toad/SQL Developer/etc), you do the following:
-- create a variable outside of PL/SQL to hold the ref cursor pointer (this is a SQL*Plus command):
variable rc refcursor;
-- populate our ref cursor variable with the pointer. Note how we pass it in as a bind variable
begin
list_emp(p_emp_id => 1234,
p_dept_id => 10,
p_ref_cur => :rc);
end;
/
-- finally, print the contents of the ref cursor.
print rc;

Raise Exception when record not found

I have a table that includes customer ID and order ID and some other data.
I want to create a procedure that takes customer ID as input and look inside the table.
if that customer exists then print the order details for that customer and
if customer does not exist then raise an exception "Customer not found."
I have this code, but it's not working properly, or maybe I have the wrong approach to this question.
CREATE OR REPLACE PROCEDURE order_details(customer NUMBER)
IS
CURSOR order_cursor IS
SELECT ORDER_ID, ORDER_DATE, TOTAL, CUSTOMER_ID
FROM PRODUCT_ORDER
WHERE CUSTOMER_ID = customer ;
order_row order_cursor%ROWTYPE ;
customer_error EXCEPTION ;
BEGIN
FOR order_row IN order_cursor
LOOP
IF order_cursor%FOUND THEN
dbms_output.put_line ('order id = ' || order_row.ORDER_ID) ;
ELSE
RAISE customer_error ;
END IF;
END LOOP;
EXCEPTION
WHEN customer_error THEN
dbms_output.put_line ('no customer' ) ;
END;
So if I run the procedure with this line
BEGIN
order_details(103);
END;
I get two results because order exists for this customer.
and if I run the procedure with this line
BEGIN
order_details(101);
END;
I don't get anything (not even the error ) because there is no order for that customer.
Table Data
You must use an "Explicit Cursor" instead of "Cursor FOR LOOP". Because the latter just enter the code between LOOP and END LOOP when the query returns more than one record.
CREATE OR REPLACE PROCEDURE order_details(customer NUMBER)
IS
CURSOR order_cursor IS
SELECT ORDER_ID, ORDER_DATE, TOTAL, CUSTOMER_ID
FROM PRODUCT_ORDER
WHERE CUSTOMER_ID = customer ;
order_row order_cursor%ROWTYPE ;
customer_error EXCEPTION ;
BEGIN
OPEN order_cursor;
LOOP
FETCH order_cursor INTO order_row;
EXIT WHEN order_cursor%NOTFOUND;
dbms_output.put_line ('order id = ' || order_row.ORDER_ID);
END LOOP;
IF order_cursor%rowcount = 0 THEN
RAISE customer_error;
END IF;
CLOSE order_cursor;
EXCEPTION
WHEN customer_error THEN
dbms_output.put_line ('no customer' ) ;
END;
Regards

Duplicate INSERT record procedure

I have problem with mu procedure which insert duplicate last record in table
example when I put INSERT..... 'AAA' I got to rows in table 'AAA' and 'AAA'
In place when I put DBMS()... in code I got tow records
I use trigger and sequence for column ID in HistoriaDismissDate but they are in good condition. I check if I dropped trigger and sequence and its the same situation
I also use viewDate but this view get mi ONE record not two
my code
CREATE OR REPLACE PROCEDURE ChangeDismissDate
IS
v_id VARCHAR2(11);
v_dateBhd DATE := TO_DATE('20491231','yyyymmdd');
v_dateDismiss DATE := TO_DATE('20491231','yyyymmdd');
v_login VARCHAR2(50);
last_id NUMBER :=0;
CURSOR cur IS
select EMP_NO, LOGIN, ODEJSCIE_BHD, ODEJSCIE_OLD FROM viewDate;
BEGIN
OPEN cur;
LOOP
FETCH cur INTO v_id,v_login,v_dateBhd,v_dateDismiss;
DBMS_OUTPUT.put_line(v_id || ' ' || v_login || ' ' || v_dateBhd || ' ' || v_dateDismiss);
UPDATE employee_tab SET DISMISS_DATE = v_dateBhd WHERE EMP_NO = v_id;
COMMIT;
INSERT INTO HistoriaDismissDate(CUSTOMER_ID,LOGIN, DATE_CHANGE, DATE_BHD, DATE_DISMISS)
VALUES(v_id,v_login, sysdate, v_dateBhd, v_dateDismiss);
COMMIT;
EXIT WHEN cur%NOTFOUND;
END LOOP;
CLOSE cur;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack);
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack);
END;
/
2 tips on your original code:
1) cursor is a very old programming technic on PL/SQL. Prefer to use FOR ... LOOP construction. It's cleaner and less error-prone! See how it works:
CREATE OR REPLACE PROCEDURE ChangeDismissDate IS
BEGIN
for cur in (select EMP_NO, LOGIN, ODEJSCIE_BHD, ODEJSCIE_OLD FROM viewDate) loop
DBMS_OUTPUT.put_line(cur.EMP_NO || ' ' || cur.login || ' ' || cur.ODEJSCIE_BHD || ' ' || cur.ODEJSCIE_OLD);
UPDATE employee_tab
SET DISMISS_DATE = cur.ODEJSCIE_BHD
WHERE EMP_NO = cur.EMP_NO;
INSERT INTO HistoriaDismissDate
( CUSTOMER_ID,LOGIN, DATE_CHANGE, DATE_BHD, DATE_DISMISS )
VALUES
( cur.EMP_NO, cur.LOGIN, sysdate, cur.ODEJSCIE_BHD, cur.ODEJSCIE_OLD, );
end loop;
end;
/
2) Never, I mean never put a commit inside your procedure. The commit should be done on the caller block or on your client-side app. When you put a commit inside your procedure, you miss the chance to rollback after running it and other procedures could not call it if they want to control the transaction flow.

PL/SQL: ORA-00942: table or view does not exist

Am getting this error 'PL/SQL: ORA-00942: table or view does not exist' in Oracle 11G when I try to runt his portion of my script. It seems the select statement isn't parsing the name of the variable from the cursor. Need help to ensure this can read the table name variable from the cursor.
DECLARE
ITEM_ERROR NUMBER;
CNT_SITE VARCHAR2(46);
CURSOR C_SITEID IS
SELECT OBJECTNAME,ATTRIBUTENAME FROM MAXATTRIBUTE WHERE ATTRIBUTENAME LIKE 'SITE%' GROUP BY OBJECTNAME,ATTRIBUTENAME, COLUMNNAME;
SITEIDRec C_SITEID%RowType;
BEGIN
BEGIN
OPEN C_SITEID;
LOOP
FETCH C_SITEID into SITEIDRec;
EXIT WHEN C_SITEID %NOTFOUND;
BEGIN
SELECT COUNT(SITEID) into CNT_SITE FROM SITEIDRec.OBJECTNAME
WHERE SITEID IN ('COLLEGE NANO SCI ENG-TGCM','FREESCALE-BALAZS','TGCM-GLOBAL FOUNDRIES','INTL RECTIFIER-TGM','TGCM-DMOS5','TGCM-IMFT','TGCM-TRIQUINT','GP-TRIQUINT');
EXCEPTION
WHEN NO_DATA_FOUND THEN NULL;
END;
END LOOP;
--COMMIT;
CLOSE C_SITEID;
--COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN NULL;
END;
--COMMIT;
EXCEPTION
WHEN OTHERS THEN
MSG_TEXT := SUBSTR(SQLERRM,1,200);
--COMMIT;
raise;
END;
I think you have FROM TableName missing in your query and hence it's rightly complaining.
SELECT COUNT(SITEID) into SITEIDRec.OBJECTNAME
WHERE SITEID IN
('COLLEGE NANO SCI ENG-TGCM','FREESCALE-BALAZS',
'TGCM-GLOBAL FOUNDRIES','INTL RECTIFIER-TGM','TGCM-DMOS5',
'TGCM-IMFT','TGCM-TRIQUINT','GP-TRIQUINT');
Please correct your query by adding the From TableName.
EDIT: Try using EXECUTE IMMEDIATE as below
EXECUTE IMMEDIATE 'SELECT COUNT(SITEID) into CNT_SITE FROM '
|| SITEIDRec.OBJECTNAME ||
' WHERE SITEID IN (''COLLEGE NANO SCI ENG-TGCM'',''FREESCALE-BALAZS'',
''TGCM-GLOBAL FOUNDRIES'',''INTL RECTIFIER-TGM'',''TGCM-DMOS5'',
''TGCM-IMFT'',''TGCM-TRIQUINT'',''GP-TRIQUINT'')';

How to solve the Issue declaring a cursor in a Procedure/Package?

I'm new to Oracle and having issues declaring a cursor within my package. Can anyone tell me what i'm doing wrong?
Thanks
CREATE OR REPLACE PACKAGE CHECK_STOCK_LEVELS AS
PROCEDURE CHECK_PAYMTS_AGAINST_INVOICES;
FUNCTION CHECK_PROD_PRICE RETURN NUMBER;
END;
/
CREATE OR REPLACE PACKAGE BODY CHECK_STOCK_LEVELS AS
FUNCTION CHECK_PROD_PRICE (INP_PROD_NAME VARCHAR2)
RETURN NUMBER
IS
PROD_CNT PRODUCT.PROD_NAME%TYPE;
BEGIN
SELECT PROD_PRICE INTO PROD_CNT
FROM PRODUCT WHERE PROD_PRICE = INP_PROD_NAME;
RETURN (PROD_CNT);
END CHECK_PROD_PRICE;
/
SELECT CHECK_STOCK_LEVELS.CHECK_PROD_PRICE(3.5mm Jack) FROM DUAL;
PROCEDURE CHECK_PAYMTS_AGAINST_INVOICES
DECLARE CURSOR SEL_PAYMTS_AND_INVS
IS
SELECT P.INVOICE_ID, P.PAYMENT_AMOUNT, I.INVOICE_AMOUNT
FROM PAYMENT P
INNER JOIN INVOICE I ON P.INVOICE_ID = I.INVOICE_ID;
V_TEMP_RESULTS_ROW SEL_PAYMTS_AND_INVS%ROWTYPE;
PAYMT_INVOICE_MISMATCH EXCEPTION;
BEGIN
OPEN SEL_PAYMTS_AND_INVS;
FETCH SEL_PAYMTS_AND_INVS INTO V_TEMP_RESULTS_ROW;
WHILE SEL_PAYMTS_AND_INVS%FOUND LOOP
IF V_TEMP_RESULTS_ROW.PAYMENT_AMOUNT != V_TEMP_RESULTS_ROW.INVOICE_AMOUNT THEN
DBMS_OUTPUT.PUT_LINE('EMPLOYEE ID : ' || V_EMPLOYEE_ROW.EMPID || ' HAS A SALARY OF : ' || V_EMPLOYEE_ROW.SALARY);
RAISE PAYMT_INVOICE_MISMATCH;
END IF;
FETCH SEL_PAYMTS_AND_INVS INTO V_TEMP_RESULTS_ROW;
END LOOP;
CLOSE SEL_PAYMTS_AND_INVS;
EXCEPTION
WHEN PAYMT_INVOICE_MISMATCH THEN
DBMS_OUTPUT.PUT_LINE('PAYMENT AMOUNT DOES NOT MATCH INVOICE AMOUNT');
RAISE;
END;
END;
This:
SELECT CHECK_STOCK_LEVELS.CHECK_PROD_PRICE(3.5mm Jack) FROM DUAL;
should be:
SELECT CHECK_STOCK_LEVELS.CHECK_PROD_PRICE('3.5mm Jack') FROM DUAL;
And this:
PROCEDURE CHECK_PAYMTS_AGAINST_INVOICES
DECLARE CURSOR SEL_PAYMTS_AND_INVS
IS
SELECT P.INVOICE_ID, P.PAYMENT_AMOUNT, I.INVOICE_AMOUNT
FROM PAYMENT P
INNER JOIN INVOICE I ON P.INVOICE_ID = I.INVOICE_ID;
V_TEMP_RESULTS_ROW SEL_PAYMTS_AND_INVS%ROWTYPE;
PAYMT_INVOICE_MISMATCH EXCEPTION;
BEGIN
...
should be:
PROCEDURE CHECK_PAYMTS_AGAINST_INVOICES
IS -- not DECLARE
CURSOR SEL_PAYMTS_AND_INVS
IS
SELECT P.INVOICE_ID, P.PAYMENT_AMOUNT, I.INVOICE_AMOUNT
FROM PAYMENT P
INNER JOIN INVOICE I ON P.INVOICE_ID = I.INVOICE_ID;
V_TEMP_RESULTS_ROW SEL_PAYMTS_AND_INVS%ROWTYPE;
PAYMT_INVOICE_MISMATCH EXCEPTION;
BEGIN
...

Resources