ora-01422 error by a procedure - oracle

Below code throwing ORA-01422 error. As my code uses select ... into I come to know it is fetching more than one row from the table but how can I overcome this by eliminating select into statement. Here is the code:
PROCEDURE Call_Transaction ( Transaction_Name Varchar2, Transaction_Type Varchar2, Form_Open_Type Varchar2 ) IS
BEGIN
Declare
M_Transaction_Name U_Transaction_Master.Transaction_Name%Type := Upper(Transaction_Name);
M_Transaction_Cd U_Transaction_Master.Transaction_Cd%Type;
T_Transaction_Cd U_Transaction_Master.Transaction_Cd%Type;
Begin
Select Transaction_Cd Into M_Transaction_Cd From U_Transaction_Master
Where Transaction_Name = M_Transaction_Name ;
Begin
Select Transaction_Cd Into T_Transaction_Cd From U_User_Wise_Transactions
Where Login_Cd = :Global.Login_Cd And Transaction_Cd = M_Transaction_Cd And
Inst_Cd = :Global.Company_Cd And
To_Char(Valid_Upto_Date,'DD-MM-YYYY') = '31-12-9999';
If Transaction_Type = 'FORM' And Upper(Form_Open_Type) = 'CALL_FORM' Then
DECLARE
id FormModule;
BEGIN
id := Find_Form(M_Transaction_Name); --<Replace your form name>--
IF Id_Null(id) THEN
Call_Form(:Global.Forms_Path||M_Transaction_Name||'.Fmx');
ELSE
Go_Form(Id) ;
END IF ;
END ;
Elsif Transaction_Type = 'FORM' And Upper(Form_Open_Type) = 'OPEN_FORM' Then
Open_Form(:Global.Forms_Path||M_Transaction_Name||'.Fmx');
Elsif Transaction_Type = 'REPORT' And Upper(Form_Open_Type) = 'RUN_PRODUCT' Then
Declare
Pl_Id ParamList;
Begin
Pl_Id := Get_Parameter_List('tmpdata');
IF NOT Id_Null(Pl_Id) THEN
Destroy_Parameter_List( Pl_Id );
END IF;
Pl_Id := Create_Parameter_List('tmpdata');
ADD_Parameter(pl_id,'Inst_Cd',TEXT_PARAMETER,:GLOBAL.Company_Cd);
ADD_Parameter(pl_id,'Ac_Year_Cd',TEXT_PARAMETER,:GLOBAL.Ac_Year_Cd);
ADD_Parameter(Pl_Id,'INST_NAME',TEXT_PARAMETER, :Global.Company_name);
ADD_Parameter(Pl_Id,'ADDRESS',TEXT_PARAMETER, :Global.Address);
ADD_Parameter(pl_id,'FOOTER',TEXT_PARAMETER,:GLOBAL.Footer);
Run_Product(REPORTS,:Global.Reports_Path||M_Transaction_Name, SYNCHRONOUS, RUNTIME,
FILESYSTEM, Pl_Id, NULL);
End;
End If;
Exception
When No_Data_Found Then
Message('Sorry..., You Do Not Have Authorization For : '||M_Transaction_Cd||' Transaction Code...');
Raise Form_Trigger_Failure;
End;
Exception
When No_Data_Found Then
Message('The Transaction Cd Not Exists In Transaction Master, Please Contact Administrator...');
Raise Form_Trigger_Failure;
End;
END;
How can I rewrite the code to resolve ORA-01422 error?

First, you need to change exception handling logic:
enclose in begin ... exception ... end only part that really can
through exception;
handle too_many_rows exception
.
PROCEDURE Call_Transaction ( Transaction_Name Varchar2, Transaction_Type Varchar2, Form_Open_Type Varchar2 ) IS
BEGIN
Declare
M_Transaction_Name U_Transaction_Master.Transaction_Name%Type := Upper(Transaction_Name);
M_Transaction_Cd U_Transaction_Master.Transaction_Cd%Type;
T_Transaction_Cd U_Transaction_Master.Transaction_Cd%Type;
Begin
-- 1st select with error analysis
begin
Select Transaction_Cd Into M_Transaction_Cd From U_Transaction_Master
Where Transaction_Name = M_Transaction_Name ;
exception
when No_Data_Found then begin
Message('The Transaction Cd Not Exists In Transaction Master, Please Contact Administrator...');
Raise Form_Trigger_Failure;
end;
when too_many_rows then begin
-- What really must be done in this case?
Message('There are too many Transaction Cd's with passed name In Transaction Master, Please Contact Administrator...');
Raise Form_Trigger_Failure;
end;
end;
-- 2nd select with error analysis
begin
Select Transaction_Cd Into T_Transaction_Cd From U_User_Wise_Transactions
Where Login_Cd = :Global.Login_Cd And Transaction_Cd = M_Transaction_Cd And
Inst_Cd = :Global.Company_Cd And
To_Char(Valid_Upto_Date,'DD-MM-YYYY') = '31-12-9999';
Exception
When No_Data_Found Then begin
Message('Sorry..., You Do Not Have Authorization For : '||M_Transaction_Cd||' Transaction Code...');
Raise Form_Trigger_Failure;
end;
When too_many_rows Then begin
-- What really must be done in this case?
Message('Sorry..., there are some misconfiguration in Authorization Settings For : '||M_Transaction_Cd||' Transaction Code. Please contact Administrator.');
Raise Form_Trigger_Failure;
end;
End;
If Transaction_Type = 'FORM' And Upper(Form_Open_Type) = 'CALL_FORM' Then
---[... all other code skipped ...]---
End If;
END;
After refactoring you need to answer a question about what really must be performed in situations when more than one row found and handle it according to nature of implemented task.
If you worried about method that you can use to detect presence of values and determine it's count then you may look at this question on StackOverflow.

In oracle, you can keep the select into statement and limit the number of rows using ROWNUM:
Select Transaction_Cd Into M_Transaction_Cd From U_Transaction_Master
Where Transaction_Name = M_Transaction_Name
and ROWNUM < 2;

Related

Unable to get dbms_sql.column_value

I'm trying to read a query from a table and process it with DBMS_SQL package. It parses correctly. I can also see the columns, which occurs in a query. But I'm not able to fetch results. In debug mode It throws the exception while trying to getting dbms_sql.column_value (please see the code below).
/*--------------------------------------------------------------------------------------------------------------------*/
PROCEDURE MY_PROC( nCSV_EXP_CFG_ID IN NUMBER,nN1 IN NUMBER DEFAULT null )
/*--------------------------------------------------------------------------------------------------------------------*/
as
l_ntt_desc_tab dbms_sql.desc_tab;
nCursorId INTEGER;
nColCnt INTEGER;
nRowCnt INTEGER;
rCSV_EXP_CFG CSV_EXP_CFG%ROWTYPE;
TYPE rowArray IS VARRAY(20) OF VARCHAR2(255);
colVal rowArray;
BEGIN
SELECT * INTO rCSV_EXP_CFG
FROM CSV_EXP_CFG
WHERE
CSV_EXP_CFG_ID = nCSV_EXP_CFG_ID;
nCursorId:=dbms_sql.open_cursor;
dbms_sql.parse(nCursorId, rCSV_EXP_CFG.EXPORT_TABLE, dbms_sql.native);
IF nN1 IS NOT NULL THEN DBMS_SQL.BIND_VARIABLE (nCursorId, 'n1', nN1); END IF;
dbms_sql.describe_columns(nCursorId, nColCnt, l_ntt_desc_tab);
FOR i IN 1..nColCnt LOOP
DBMS_OUTPUT.PUT_LINE( l_ntt_desc_tab(i).col_name);
--DBMS_SQL.DEFINE_COLUMN(nCursorId, i, colVal(i), 255);
END LOOP;
nRowCnt:=dbms_sql.execute(nCursorId);
LOOP
EXIT WHEN dbms_sql.fetch_rows(nCursorId) = 0;
FOR i IN 1..nColCnt LOOP
--here I'm getting the exception
dbms_sql.column_value(nCursorId, i, colVal(i));
END LOOP;
END LOOP;
Dbms_sql.close_cursor(nCursorId);
EXCEPTION WHEN OTHERS THEN
NULL;
END MY_PROC;
What am I doing wrong?

NO DATA FOUND oracle using cursor

I have been searching online using different solution suggestion to handle no data in this code but to no avail. how can I handle the exception if no data is found. How can I solve this problem. I am not an expert in oracle though!
DECLARE
nCheckOption INT;
no_data_found EXCEPTION;
CURSOR TYPE_cursor IS
SELECT
D_NAL_REF.TRANS
, D_NAL_REF.INJ
, D_NAL_REF.REF
FROM D_NAL_REF D_NAL_REF
WHERE D_NAL_REF.REF IN
(SELECT AG_REF.REF
FROM AG_REF A_REF
WHERE A_REF.DESCEND_REF = 10
);
BEGIN
FOR rec IN TYPE_cursor
LOOP
nCheckOption := 0;
SELECT 1
INTO nCheckOption
FROM PERSON_TYPE WHERE TRANS = rec.TRANS AND INJ = rec.INJ;
IF nCheckOption = 1 THEN
UPDATE PERSON_TYPE
SET PERSON_TYPE.TYPE = rec.REF
WHERE TRANS = rec.TRANS
AND PERSON_TYPE.INJ = rec.INJ;
END IF;
EXCEPTION
WHEN no_data_found
THEN
DBMS_OUTPUT.PUT_LINE ('Trapped the error!?');
END LOOP;
END;
/
Rewrite your code to eliminate the inner SELECT, which is the only place in your code where I can see that a NO_DATA_FOUND exception could possibly be raised:
BEGIN
FOR rec IN (SELECT d.TRANS,
d.INJ,
d.REF
FROM D_NAL_REF d
WHERE d.REF IN (SELECT a.REF
FROM AG_REF a
WHERE a.DESCEND_REF = 10) AND
(d.TRANS, d.INJ) IN (SELECT DISTINCT TRANS, INJ
FROM PERSON_TYPE))
LOOP
UPDATE PERSON_TYPE
SET TYPE = rec.REF
WHERE TRANS = rec.TRANS AND
INJ = rec.INJ;
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Trapped the error!?');
END;
I think you need to find if cursor contains any record or not. If cursor is empty then it must return that error message written in exception block.
Or you want to print error message if update statement do not find any record to update.
Here is the pseudo code.
Declare
ncheckoption number := 0;
Cursor type_cursor is ....
Begin
For rec in type_cursor loop
ncheckoption := ncheckoption + 1;
Update ...
If sql%rowcount = 0 then
Dbms_output.put_line('error message, if you want here in case no record found in table to update');
-- loop will continue
-- if you want loop to break then issue exit statement here
End if;
End loop;
If ncheckoption = 0 then
Dbms_output.put_line('error message you want to print in case cursor is empty');
End if;
End;
/
Cheers!!

Catch ORA exceptions in PL/SQL

I wrote a package to add records in a country table that has a reference key pointing to a "regions" table using region_id.So,if I try to add a "region_id" in my countries table and if that value does not exist in my regions table,I should throw the exception and catch.
My package code is:
CREATE PACKAGE BODY cus7 AS
v_error_code NUMBER;
region_exists pls_integer;
procedure addi6 (c_cntry_id in out countries.country_id%type,
c_cntr_name in countries.country_name%type,
c_rgn_id in countries.region_id%type)
is
begin
begin
select 1 into region_exists
from regions r
where r.region_id = c_rgn_id;
exception
when no_data_found then
region_exists := 0;
DBMS_OUTPUT.PUT_LINE('Region not present');
end;
if region_exists = 1 then
insert into countries(country_id, country_name,region_id)
values (c_cntry_id, c_cntr_name, c_rgn_id);
DBMS_OUTPUT.PUT_LINE('Inserted');
END IF;
EXCEPTION
WHEN dup_val_on_index
THEN
c_cntry_id := null;
DBMS_OUTPUT.PUT_LINE('Already present');
end addi6;
END cus7;
/
Now,in my procedure,everything is working fine,except when I do an add like this:
DECLARE
outputValue CHAR(2) := 'KO';
begin
cus7.addi6(outputValue,'KOREA',5);
end;
/
apart from getting my own message which is "Region not found",I am also getting ORA-01403-No data found.
My question is if there is a way to catch this ORA exception or avoid display?
Tx in advance
Yes, all you have to do is add WHEN OTHERS to your exception block in order to catch all of the other possible ORA exceptions.
EXCEPTION
WHEN dup_val_on_index
THEN
c_cntry_id := null;
DBMS_OUTPUT.PUT_LINE('Already present')
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE('Another Error');
-- other logic here
Here is an extensive documentation regarding error handling in PL/SQL.

How do you make DBMS_DATAPUMP error if there's an error?

DBMS_DATAPUMP doesn't fail when the columns in the source and destination tables do not match. This means that no exceptions are raised. I'm trying to use the GET_STATUS procedure in order to understand if there are any errors but unfortunately there doesn't seem to be...
My ultimate goal is for DBMS_DATAPUMP to raise an exception if the import fails. Differing columns is an easy example to work with as I know that it should fail.
Here's my current code (I've obscured schema names purposefully). The environment I'm using is identical on both servers save that I've added an extra column to the source table. I also perform a count of the number of rows in the table.
connect schema/*#db1/db1
-- */
create table tmp_test_datapump as
select u.*, cast(null as number) as break_it
from user_tables u;
Table created.
select count(*) from tmp_test_datapump;
COUNT(*)
----------
1170
connect schema/*#db2/db2
-- */
set serveroutput on
create table tmp_test_datapump as
select u.*
from user_tables u;
Table created.
In attempting to test this the DATAPUMP code has got a little more complicated. Everything in the infinite loop can be removed and this would act the same.
declare
l_handle number;
l_status varchar2(255);
l_job_state varchar2(4000);
l_ku$status ku$_status1020;
begin
l_handle := dbms_datapump.open( operation => 'IMPORT'
, job_mode => 'TABLE'
, remote_link => 'SCHEMA.DB.DOMAIN.COM'
, job_name => 'JOB_TEST_DP'
, version => 'COMPATIBLE' );
dbms_datapump.set_parameter( handle => l_handle
, name => 'TABLE_EXISTS_ACTION'
, value => 'TRUNCATE');
dbms_datapump.metadata_filter( handle => l_handle
, name => 'NAME_EXPR'
, value => 'IN (''TMP_TEST_DATAPUMP'')');
dbms_datapump.start_job(handle => l_handle);
while true loop
dbms_datapump.wait_for_job(handle => l_handle,job_state => l_status);
if l_status in ('COMPLETED','STOPPED') then
exit;
end if;
dbms_datapump.get_status( handle => l_handle
, mask => dbms_datapump.KU$_STATUS_JOB_ERROR
, job_state => l_job_state
, status => l_ku$status);
dbms_output.put_line('state: ' || l_job_state);
if l_ku$status.error is not null and l_ku$status.error.count > 0 then
for i in l_ku$status.error.first .. l_ku$status.error.last loop
dbms_output.put_line(l_ku$status.error(i).logtext);
end loop;
end if;
end loop;
end;
/
PL/SQL procedure successfully completed.
select count(*) from tmp_test_datapump;
COUNT(*)
----------
47
As you can see the number of records in the tables is different; the import has failed and no exception has been raised. Various blogs and DBA.SE questions imply that some sort of error catching can be done; but I can't seem to manage it.
How can you catch fatal errors in a DBMS_DATAPUMP import?
I'm working with dbms_datapump package right know. The following procedure is searching one table for schemas that will be exported. BACKUP_INFO_MOD is a procedure with PRAGMA AUTONOMOUS TRANSACTION that's making logs in another table.
Example 6.3 from this document helped me a lot. Here's fragment from my code (with additional commentary):
CREATE OR REPLACE PROCEDURE BACKUP_EXECUTE (
threads in number := 1
, dir in varchar2 := 'DATA_PUMP_DIR'
) AS
schemas varchar2(255);
filename varchar2(255);
path varchar2(255);
errormsg varchar2(4000);
handle number;
job_state varchar2(30);
--variables under this line are important to error handling
logs ku$_LogEntry;
lindx pls_integer;
status ku$_Status;
exporterr exception; --our exception to handle export errors
[...]
BEGIN
[...]
schemas:=schema_list(indx).schema_name;
--Full dir path for logs
select directory_path into path from dba_directories where directory_name=dir;
--If data not found then automatically raise NO_DATA_FOUND
select to_char(sysdate, 'YYMMDDHH24MI-')||lower(schemas)||'.dmp' into filename from dual;
backup_info_mod('insert',path||filename,schemas);
begin --For inner exception handling on short fragment
handle := dbms_datapump.open('EXPORT','SCHEMA');
dbms_datapump.add_file(handle, filename, dir); --dump file
dbms_datapump.add_file(handle, filename||'.log', dir,null,DBMS_DATAPUMP.KU$_FILE_TYPE_LOG_FILE); --export log file
dbms_datapump.metadata_filter(handle, 'SCHEMA_EXPR', 'IN ('''||schemas||''')');
dbms_datapump.set_parallel(handle,threads);
backup_info_mod(file_name=>path||filename, curr_status=>'IN PROGRESS');
dbms_datapump.start_job(handle);
--If job didn't start due to some errors, then let's get some information
exception
when others then
dbms_datapump.get_status(handle,8,0,job_state,status);
--This will overwrite our job_state and status
end;
--Let's go handle error if job_state was overwritten
if job_state is not null then
raise exporterr;
else
job_state:='UNDEFINED';
end if;
--Checking in loop if errors occurred. I'm not using wait_for_job
--because it didn't work out
while (job_state != 'COMPLETED') and (job_state != 'STOPPED') loop
--Like before, let's get some information
dbms_datapump.get_status(handle,8,-1,job_state,status);
--Looking for errors using mask
if (bitand(status.mask,dbms_datapump.ku$_status_job_error) != 0) then
--If occurred: let's stop the export job and raise an error
dbms_datapump.stop_job(handle);
dbms_datapump.detach(handle);
raise exporterr;
exit;
end if;
end loop;
backup_info_mod(file_name=>path||filename, curr_status=>'COMPLETED');
dbms_datapump.detach(handle);
exception
when NO_DATA_FOUND then
backup_info_mod('insert',null,schemas,'ERROR','No '||dir||' defined in dba_directories');
when exporterr then
--Let's get all error messages and write it to errormsg variable
logs:=status.error;
lindx:=logs.FIRST;
while lindx is not null loop
errormsg:=errormsg||logs(lindx).LogText;
lindx:=logs.NEXT(lindx);
if lindx is not null then
errormsg:=errormsg||' | '; --Just to separate error messages
end if;
end loop;
backup_info_mod(
file_name=>path||filename,
curr_status=>'ERROR',
errormsg=>errormsg);
/*when other then --TODO
null;
*/
end;
END BACKUP_EXECUTE;
You can put the datapump command in a shell script when the log is created for the impdp, and before you end the shell script you can check the log for IMP- errors or ORA- errors, if true warn the user to look at the log file for errors.
The provided document from yammy is good.
I faced the same problem when using the dbms_datapump package to import a DB dump. Even there are error during the import, the job is treated as success / finished. By using the code example in the document, i could get the error / log message during the import. I then check if there are 'ORA-' found in the log message and throw a custom error when the import job is finished.
Following is the sample code:
PROMPT CREATE OR REPLACE PROCEDURE import_schema
CREATE OR REPLACE PROCEDURE import_db_dump (
dumpFilename IN VARCHAR2)
IS
handle NUMBER; -- Handler of the job
loopIdx NUMBER; -- Loop index
percentDone NUMBER; -- Percentage of job complete
jobState VARCHAR2(30); -- To keep track of job state
ku_logEntry ku$_LogEntry; -- For WIP and error messages
ku_jobStatus ku$_JobStatus; -- The job status from get_status
ku_jobDescjd ku$_JobDesc; -- The job description from get_status
ku_Status ku$_Status; -- The status object returned by get_status
errorCount NUMBER;
import_error_found EXCEPTION;
BEGIN
handle := dbms_datapump.open (
operation => 'IMPORT',
job_mode => 'SCHEMA');
dbms_output.put_line('Define table exists action: truncate');
dbms_datapump.set_parameter (
handle => handle,
name => 'TABLE_EXISTS_ACTION',
value => 'TRUNCATE');
dbms_output.put_line('Define dumpfilename: ' || dumpFilename);
dbms_datapump.add_file (
handle => handle,
filename => dumpFilename,
filetype => dbms_datapump.ku$_file_type_dump_file);
dbms_output.put_line('Start datapump job');
dbms_output.put_line('==================');
dbms_datapump.start_job (handle);
-- Ref: http://docs.oracle.com/cd/E11882_01/server.112/e22490/dp_api.htm#SUTIL977
-- The import job should now be running. In the following loop, the job is
-- monitored until it completes. In the meantime, progress information is
-- displayed.
percentDone := 0;
jobState := 'UNDEFINED';
errorCount := 0;
WHILE (jobState != 'COMPLETED') AND (jobState != 'STOPPED') LOOP
dbms_datapump.get_status(handle,
dbms_datapump.ku$_status_job_error +
dbms_datapump.ku$_status_job_status +
dbms_datapump.ku$_status_wip,
-1, jobState, ku_Status);
ku_jobStatus := ku_Status.job_status;
-- If the percentage done changed, display the new value.
IF ku_jobStatus.percent_done != percentDone THEN
dbms_output.put_line('*** Job percent done = ' ||
to_char(ku_jobStatus.percent_done));
percentDone := ku_jobStatus.percent_done;
END IF;
-- If any work-in-progress (WIP) or Error messages were received for the job,
-- display them.
IF (bitand(ku_Status.mask, dbms_datapump.ku$_status_wip) != 0) THEN
ku_logEntry := ku_Status.wip;
ELSE
IF (bitand(ku_Status.mask,dbms_datapump.ku$_status_job_error) != 0) THEN
ku_logEntry := ku_Status.error;
ELSE
ku_logEntry := null;
END IF;
END IF;
IF ku_logEntry IS NOT NULL THEN
loopIdx := ku_logEntry.FIRST;
WHILE loopIdx IS NOT NULL LOOP
dbms_output.put_line(ku_logEntry(loopIdx).LogText);
IF INSTR(ku_logEntry(loopIdx).LogText, 'ORA-') > 0 THEN
errorCount := errorCount + 1;
dbms_output.put_line('^^^^---ERROR FOUND');
END IF;
loopIdx := ku_logEntry.NEXT(loopIdx);
END LOOP;
END IF;
END LOOP;
-- Indicate that the job finished and gracefully detach from it.
dbms_output.put_line('Job has completed');
dbms_output.put_line('Final job state = ' || jobState);
dbms_datapump.detach(handle);
IF errorCount > 0 THEN
RAISE import_error_found;
END IF;
EXCEPTION
WHEN import_error_found THEN
dbms_output.put_line('Error found when import. Number of error: ' || errorCount);
RAISE;
WHEN OTHERS THEN
dbms_output.put_line('[Error Backtrace]');
dbms_output.put_line(dbms_utility.format_error_backtrace());
dbms_output.put_line('[Call Stack]');
dbms_output.put_line(dbms_utility.format_call_stack());
dbms_datapump.stop_job(handle);
RAISE;
END;
/
Hope this help.

oracle declare user defined exception

Oracle SP not compiling
I am expierenced at MS SQL but taking a class in Oracle and for the life of me cannot figure out why this script for a stored Procedure will not work. I am getting an error in the variable declaration section at the first Exception variable. here is the error message:
PLS-00103: Encountered the symbol "EXCEPTION" when expecting one of the following:
in out <an identifier> <a double-quoted delimited-identifier> LONG_ double ref char
time timestamp interval date binary national character nchar
The code
CREATE or REPLACE Procedure Movie_Rental_SP
(
Mv_ID IN Number,
Mem_ID IN Number,
Pay_ID IN Number,
Mv_Chk Number,
Mem_Chk Number,
Pay_Chk Number,
Qty_Chk Number,
--> next line is where the error points
UnKnown_Mv Exception,
UnKnown_Mem Exception,
UnKnown_Pay Exception,
UnAvail_Mv Exception )
IS
BEGIN
SELECT COUNT(Movie_ID) INTO Mv_Chk FROM MM_Movie WHERE Movie_ID = Mv_ID;
SELECT COUNT(Member_ID) INTO Mem_Chk FROM MM_Member WHERE Member_ID = Mem_ID;
SELECT COUNT(Payment_Methods_ID) INTO Pay_Chk FROM MM_Pay_Type WHERE Payment_Methods_ID = Pay_ID;
SELECT Movie_Qty INTO Qty_Chk FROM MM_Movie WHERE Movie_ID = Mv_ID;
IF Mv_Chk = 0 THEN RAISE UnKnown_Mv;
ELSE IF Mem_Chk = 0 THEN RAISE UnKnown_Mem;
ELSE IF Pay_Chk = 0 THEN RAISE UnKnown_Pay;
ELSE Qty_Chk = 0 THEN RAISE UnAvail_Mv;
END IF;
DECLARE New_ID NUMBER;
BEGIN
SELECT Max(Rental_ID)+1 INTO New_ID FROM MM_Rental;
EXCEPTION WHEN NO_DATA_FOUND THEN
New_ID := 1;
DBMS_OUTPUT.PUT_LINE ('There are no exsisting Rental IDs, ID set to 1');
END;
INSERT INTO MM_Rental VALUES (New_ID,Mem_ID,Mv_ID,Sysdate,Null,Pay_ID);
UPDATE MM_Movie SET Movie_Qty = Movie_Qty - 1 WHERE Movie_ID = Mv_ID;
EXCEPTION
WHEN UnKnown_Mv THEN
RAISE_APPLICATION_ERROR(-20001,'There is no movie with Movie ID of: '||Mv_ID||' Transaction cancelled.');
WHEN UnKnown_Mem THEN
RAISE_APPLICATION_ERROR(-20002,'No member exists with member ID: '||Mem_ID||' Transaction cancelled.');
WHEN UnKnown_Pay THEN
RAISE_APPLICATION_ERROR(-20003,'No payment type for: '||Pay_ID||' Transaction cancelled.');
WHEN UnAvail_Mv THEN
RAISE_APPLICATION_ERROR(-20004,'No movies available for: '||Mv_ID||' Transaction cancelled.');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ('Error number: '||sqlcode);
DBMS_OUTPUT.PUT_LINE ('Error message: '||sqlerrm);
DBMS_OUTPUT.PUT_LINE('Unanticipated error. Contact your system administrator.');
END;
/
Any help would be greatly appreciated!
My assumption is that after the three IN parameters, your intention is to declare everything else as a local variable, not as parameters to the procedure. It wouldn't make sense to pass exceptions to a procedure. Your 'ELSE IFalso needs to beELSIF`.
CREATE or REPLACE Procedure Movie_Rental_SP
(
Mv_ID IN Number,
Mem_ID IN Number,
Pay_ID IN Number
)
AS
Mv_Chk Number;
Mem_Chk Number;
Pay_Chk Number;
Qty_Chk Number;
UnKnown_Mv Exception;
UnKnown_Mem Exception;
UnKnown_Pay Exception;
UnAvail_Mv Exception;
BEGIN
SELECT COUNT(Movie_ID) INTO Mv_Chk FROM MM_Movie WHERE Movie_ID = Mv_ID;
SELECT COUNT(Member_ID) INTO Mem_Chk FROM MM_Member WHERE Member_ID = Mem_ID;
SELECT COUNT(Payment_Methods_ID) INTO Pay_Chk FROM MM_Pay_Type WHERE Payment_Methods_ID = Pay_ID;
SELECT Movie_Qty INTO Qty_Chk FROM MM_Movie WHERE Movie_ID = Mv_ID;
IF Mv_Chk = 0 THEN RAISE UnKnown_Mv;
ELSIF Mem_Chk = 0 THEN RAISE UnKnown_Mem;
ELSIF Pay_Chk = 0 THEN RAISE UnKnown_Pay;
ELSE Qty_Chk = 0 THEN RAISE UnAvail_Mv;
END IF;
DECLARE
New_ID NUMBER;
BEGIN
SELECT Max(Rental_ID)+1 INTO New_ID FROM MM_Rental;
EXCEPTION WHEN NO_DATA_FOUND THEN
New_ID := 1;
DBMS_OUTPUT.PUT_LINE ('There are no exsisting Rental IDs, ID set to 1');
END;
INSERT INTO MM_Rental VALUES (New_ID,Mem_ID,Mv_ID,Sysdate,Null,Pay_ID);
UPDATE MM_Movie SET Movie_Qty = Movie_Qty - 1 WHERE Movie_ID = Mv_ID;
EXCEPTION
WHEN UnKnown_Mv THEN
RAISE_APPLICATION_ERROR(-20001,'There is no movie with Movie ID of: '||Mv_ID||' Transaction cancelled.');
WHEN UnKnown_Mem THEN
RAISE_APPLICATION_ERROR(-20002,'No member exists with member ID: '||Mem_ID||' Transaction cancelled.');
WHEN UnKnown_Pay THEN
RAISE_APPLICATION_ERROR(-20003,'No payment type for: '||Pay_ID||' Transaction cancelled.');
WHEN UnAvail_Mv THEN
RAISE_APPLICATION_ERROR(-20004,'No movies available for: '||Mv_ID||' Transaction cancelled.');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ('Error number: '||sqlcode);
DBMS_OUTPUT.PUT_LINE ('Error message: '||sqlerrm);
DBMS_OUTPUT.PUT_LINE('Unanticipated error. Contact your system administrator.');
END;
/
As a general principle, a WHEN OTHERS exception handler that does not re-raise the exception is almost certainly an error. Writing data to dbms_output does not in any way guarantee that the data will be seen by anyone or persisted anywhere. So, for example
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ('Error number: '||sqlcode);
DBMS_OUTPUT.PUT_LINE ('Error message: '||sqlerrm);
DBMS_OUTPUT.PUT_LINE('Unanticipated error. Contact your system administrator.');
RAISE;
will re-throw whatever exception was previously raised. Of course, you'd get the same behavior if you simply didn't catch exceptions that you can't handle.

Resources