Bulk collect and forall with save exception - exception

I have the below code , emp1 table has data of 12 rows in which 2 empno's already present in emp table. i'm trying to save the exceptions for these 2 records and to insert remaining all to emp. But everything is getting error out and i couldn't able to insert into emp. Anyone please help.
SET SERVEROUTPUT ON;
DECLARE
CURSOR C1
IS
SELECT EMPNO FROM EMP1;
TYPE T
IS
TABLE OF C1%ROWTYPE;
L_DATA T;
L_ERRORS_COUNT NUMBER;
EX_DML_ERRORS EXCEPTION;
PRAGMA EXCEPTION_INIT (ex_DML_ERRORS, -47);
L_ERRNO NUMBER;
L_MSG VARCHAR2(4000);
L_IDX NUMBER;
BEGIN
OPEN C1;
LOOP
FETCH C1 BULK COLLECT INTO L_DATA;
BEGIN
FORALL I IN 1..L_DATA.COUNT SAVE EXCEPTIONS
INSERT
INTO EMP
(
EMPNO,
ENAME,
MGR
)
VALUES
(
L_DATA(I).EMPNO,
'SCOTT',
L_DATA(I).EMPNO
);
EXCEPTION
WHEN dup_val_on_index THEN
DBMS_OUTPUT.PUT_LINE('WHD');
L_ERRORS_COUNT := SQL%BULK_EXCEPTIONS.COUNT;
DBMS_OUTPUT.PUT_LINE('WHD::::'||L_ERRORS_COUNT);
FOR J IN 1..L_ERRORS_COUNT
LOOP
L_ERRNO := SQL%BULK_EXCEPTIONS
(
J
)
.ERROR_CODE;
L_MSG := SQLERRM(-L_ERRNO);
L_IDX := SQL%BULK_EXCEPTIONS(J).ERROR_INDEX;
DBMS_OUTPUT.PUT_LINE('I am here SVS:'||L_ERRNO||':'|| L_MSG||':'||L_IDX);
--INSERT INTO EMPS_EXC1(SQLC ,SQLE ,INDX ) VALUES(L_ERRNO, L_MSG,L_IDX);
DBMS_OUTPUT.PUT_LINE('I am here SVS:'||L_ERRNO||':'|| L_MSG||':'||L_IDX);
END LOOP;
END;
EXIT
WHEN C1%NOTFOUND;
END LOOP;
CLOSE C1;
END;

Related

Handle exceptions on procedures PL/SQL

Hi I would like to handle exceptions on my procedures to make it more useful.
My procedure adding occupations and it's wage, here is table:
CREATE TABLE Occupations(
id_oc NUMBER(2),
Name_oc VARCHAR2(20) CONSTRAINT OC_name_cc NOT NULL ,
Min_wage NUMBER(7,2) CONSTRAINT OC_min_wg NOT NULL CHECK(Min_wage>100),
CONSTRAINT Oc_id_pk PRIMARY KEY (id_oc),
CONSTRAINT OC_na UNIQUE (Name_oc)
);
Here is the procedure
create or replace procedure zad_2a(name varchar2, min_wage number)
is
isFound occupations.name_oc%TYPE;
cursor c1
is
select name_oc from occupations where name_oc = name;
begin
open c1;
fetch c1 into isFound;
if c1%found then dbms_output.put_line('Occupation already exists');
else insert into occupations values(Seq_Occupations.NEXTVAL, name, min_wage);
end if;
close c1;
end;
/
This procedure should have following exceptions:
When I set wage fewer than 100 and more than 5000
While I add bad occupation name - using numbers instead of characters
handling other unexcepted errors
How to do this?
You can try as below and modify as per your requirements.
CREATE OR REPLACE PROCEDURE zad_2a (ename VARCHAR2, min_wage NUMBER)
IS
isfound occupations.name_oc%TYPE;
e_custom_exception EXCEPTION;
PRAGMA EXCEPTION_INIT (e_custom_exception, -20001);
l_count_int NUMBER;
CURSOR c1
IS
SELECT name_oc
FROM occupations
WHERE name_oc = ename;
BEGIN
IF (min_wage < 100 OR min_wage > 5000)
THEN
RAISE e_custom_exception;
END IF;
SELECT COUNT (*)
INTO l_count_int
FROM DUAL
WHERE REGEXP_LIKE (ename, '[[:digit:]]');
IF (l_count_int > 0)
THEN
RAISE e_custom_exception;
END IF;
OPEN c1;
FETCH c1 INTO isfound;
IF c1%FOUND
THEN
DBMS_OUTPUT.put_line ('Occupation already exists');
ELSE
INSERT INTO occupations
VALUES (Seq_Occupations.NEXTVAL, ename, min_wage);
END IF;
CLOSE c1;
EXCEPTION
WHEN e_custom_exception
THEN
DBMS_OUTPUT.put_line (SQLERRM);
WHEN OTHERS
THEN
RAISE;
END;
/

FORALL update is updating only last record from collection and it's giving error ORA-22160: element at index [1] does not exist error message

FORALL update is updating only last record from collection and it's giving error ORA-22160: element at index [1] does not exist. I have scenario were i have to update million of records. When i execute the below code the update is happening only for the 100th record remaining 99 records remains same( i tested with 100 records). after execution it's giving ORA-22160: element at index [1] does not exist. i am using oracle 9i database.need suggestion for this issue.
Declare
CURSOR tk_iflow_cur
IS
SELECT DISTINCT top.rule_id,
top.rule_item_id,
msib.segment2
FROM iflow_rules top,
iflow_active_rules msib
WHERE top.rule_id = msib.rule_item_id
AND msib.organization_id = 5039 and rownum<=100
ORDER BY top.ora_inv_item_id; -- cursor fetches 100 row
---Variable declaration
TYPE l_iflow_id
IS
TABLE OF VARCHAR2(200) INDEX BY BINARY_INTEGER;
TYPE l_iflow_org
IS
TABLE OF NUMBER INDEX BY BINARY_INTEGER;
TYPE l_iflow_inv_id
IS
TABLE OF NUMBER INDEX BY BINARY_INTEGER;
TYPE l_r12_inv_id
IS
TABLE OF NUMBER;
TYPE l_r12_item_key
IS
TABLE OF VARCHAR2(200) INDEX BY BINARY_INTEGER;
TYPE l_r12_iflow
IS
TABLE OF VARCHAR2(200) INDEX BY BINARY_INTEGER;
TYPE l_omar_item_id
IS
TABLE OF NUMBER INDEX BY BINARY_INTEGER;
TYPE l_omar_seg2
IS
TABLE OF VARCHAR2(200) INDEX BY BINARY_INTEGER;
tk_iflow_id l_iflow_id;
tk_iflow_org l_iflow_org;
tk_iflow_inv_id l_iflow_inv_id;
t_omar_item_id l_omar_item_id;
t_omar_seg2 l_omar_seg2;
r12_inv_id l_r12_inv_id:=l_r12_inv_id();
r12_item_key l_r12_item_key;
r12_iflow l_r12_iflow;
user_excep EXCEPTION;
v_err_count NUMBER;
PRAGMA EXCEPTION_INIT (user_excep, -24381);
r12_item_id2 VARCHAR2(200);
BEGIN --
tk_iflow_id.DELETE;
tk_iflow_inv_id.DELETE;
OPEN tk_iflow_cur;
LOOP --Cursor Loop
tk_iflow_id.DELETE;
tk_iflow_inv_id.DELETE;
t_omar_seg2.DELETE;
FETCH tk_iflow_cur BULK COLLECT INTO tk_iflow_id, tk_iflow_inv_id, t_omar_seg2; ---100 records assigned to variables
FOR i IN 1..tk_iflow_id.COUNT -- to store the cursor value
LOOP --for Loop
BEGIN
--Comment : passing the cursor value to derive new records from different instance for updating the records
SELECT DISTINCT segment1,
inventory_item_id,
item_type
INTO r12_iflow(i),
r12_item_id2,
r12_item_key(i)
FROM iflow.ifl_active_rules#R12_db_link
WHERE segment1 =tk_iflow_id(i)
AND NVL(SEGMENT2,'NULL') = NVL(t_omar_seg2(i),'NULL')
AND organization_id =5063;
EXCEPTION
WHEN OTHERS THEN
r12_inv_id(i) := 0;
r12_item_key(i) := 0;
END;
r12_inv_id :=l_r12_inv_id();
r12_inv_id.EXTEND (i);
r12_inv_id (i) := r12_item_id2;
END LOOP; --end for loop
BEGIN
FORALL i IN r12_inv_id.FIRST..r12_inv_id.LAST SAVE EXCEPTIONS -- for all the derived records i'm updating the target table.100 records i'm updating
UPDATE iflow_active_rules
SET ora_org_id =5063,
ora_inv_item_id =r12_inv_id(i)
WHERE iflow_id =r12_iflow(i)
AND ora_inv_item_id = tk_iflow_inv_id(i);
EXCEPTION
WHEN user_excep THEN
v_err_count := SQL%BULK_EXCEPTIONS.COUNT;
FOR i IN 1 .. v_err_count
LOOP
DBMS_OUTPUT.put_line ( 'Error: ' || i || ' Array Index: ' || SQL%BULK_EXCEPTIONS (i).ERROR_INDEX || ' Message: ' || SQLERRM (SQL%BULK_EXCEPTIONS (i).ERROR_CODE) );
END LOOP;
END;
BEGIN
FORALL i IN r12_inv_id.FIRST .. r12_inv_id.LAST SAVE EXCEPTIONS
UPDATE iflow_rules --- updating openup system iflow cost details
SET ora_org_id =5063,
ora_inv_item_id =r12_inv_id(i)
WHERE iflow_id =r12_iflow(i)
AND ora_inv_item_id = tk_iflow_inv_id(i) ;
EXCEPTION
WHEN user_excep THEN
v_err_count := SQL%BULK_EXCEPTIONS.COUNT;
FOR i IN 1 .. v_err_count
LOOP
DBMS_OUTPUT.put_line ( 'Error: ' || i || ' Array Index: ' || SQL%BULK_EXCEPTIONS (i).ERROR_INDEX || ' Message: ' || SQLERRM (SQL%BULK_EXCEPTIONS (i).ERROR_CODE) );
END LOOP;
END;
EXIT
WHEN tk_iflow_id.COUNT=0;
COMMIT;
END LOOP; --End Cursor Loop
CLOSE tk_iflow_cur;
END;
This is happening because you are using r12_iflow collection in the scope of collection r12_inv_id where it not not accessible. FORALL statement is differnt the FOR LOOP. Even though they work pretty on same logic but they differs on scope of usage of variables. You can create a RECORD in your case and do the processing. See below how you can do it. PS Not tested.
DECLARE
CURSOR tk_iflow_cur
IS
SELECT DISTINCT top.rule_id, top.rule_item_id, msib.segment2
FROM iflow_rules top, iflow_active_rules msib
WHERE top.rule_id = msib.rule_item_id
AND msib.organization_id = 5039
AND ROWNUM <= 100
ORDER BY top.ora_inv_item_id; -- cursor fetches 100 row
Type var_cur is table of tk_iflow_cur%rowtype index by pls_integer;
l_cur var_cur;
--Record of your variables.
TYPE var_rec is RECORD
(
l_r12_iflow VARCHAR2 (200),
l_r12_inv_id number,
l_r12_item_key VARCHAR2 (200)
);
TYPE rec is table of var_rec index by pls_integer;
--Variable declared to hold the result of your cursor.
l_rec rec;
user_excep EXCEPTION;
v_err_count NUMBER;
PRAGMA EXCEPTION_INIT (user_excep, -24381);
r12_item_id2 VARCHAR2 (200);
BEGIN
OPEN tk_iflow_cur;
LOOP --Cursor Loop
FETCH tk_iflow_cur BULK COLLECT INTO l_cur LIMIT 100; ---100 records assigned to variables
FOR i IN 1 .. l_cur.COUNT -- to store the cursor value
LOOP --for Loop
BEGIN
--Comment : passing the cursor value to derive new records from different instance for updating the records
SELECT DISTINCT segment1, inventory_item_id, item_type
INTO l_rec(i).l_r12_iflow ,l_rec(i).l_r12_inv_id ,l_rec(i).l_r12_item_key
FROM iflow.ifl_active_rules#R12_db_link
WHERE segment1 = l_cur(i).rule_id
AND NVL (SEGMENT2, 'NULL') = NVL (l_cur(i).segment2 , 'NULL')
AND organization_id = 5063;
EXCEPTION
WHEN OTHERS
THEN
l_rec(i).l_r12_iflow := 0;
l_rec(i).l_r12_inv_id:= 0;
l_rec(i).l_r12_item_key := '';
END;
END LOOP; --end for loop
BEGIN
FORALL i IN 1 .. l_rec.COUNT SAVE EXCEPTIONS -- for all the derived records i'm updating the target table.100 records i'm updating
UPDATE iflow_active_rules
SET ora_org_id = 5063,
ora_inv_item_id = l_rec(i).l_r12_inv_id
WHERE iflow_id = l_rec(i).l_r12_iflow
AND ora_inv_item_id = l_rec(i).l_r12_inv_id;
EXCEPTION
WHEN user_excep
THEN
v_err_count := SQL%BULK_EXCEPTIONS.COUNT;
FOR i IN 1 .. v_err_count
LOOP
DBMS_OUTPUT.put_line (
'Error: '
|| i
|| ' Array Index: '
|| SQL%BULK_EXCEPTIONS (i).ERROR_INDEX
|| ' Message: '
|| SQLERRM (SQL%BULK_EXCEPTIONS (i).ERROR_CODE));
END LOOP;
END;
BEGIN
FORALL i IN 1..l_rec.COUNT SAVE EXCEPTIONS
UPDATE iflow_rules --- updating openup system iflow cost details
SET ora_org_id = 5063,
ora_inv_item_id = l_rec(i).l_r12_inv_id
WHERE iflow_id = l_rec(i).l_r12_iflow
AND ora_inv_item_id = l_rec(i).l_r12_inv_id;
EXCEPTION
WHEN user_excep
THEN
v_err_count := SQL%BULK_EXCEPTIONS.COUNT;
FOR i IN 1 .. v_err_count
LOOP
DBMS_OUTPUT.put_line (
'Error: '
|| i
|| ' Array Index: '
|| SQL%BULK_EXCEPTIONS (i).ERROR_INDEX
|| ' Message: '
|| SQLERRM (SQL%BULK_EXCEPTIONS (i).ERROR_CODE));
END LOOP;
END;
EXIT WHEN tk_iflow_cur%NOTFOUND;
END LOOP; --End Cursor Loop
COMMIT;
CLOSE tk_iflow_cur;
END;

PL/SQL: ORA-00932: inconsistent datatypes: expected NUMBER got USER_NAME.VARCHAR_ARRAY

The below is a function that I am creating to accept an array of varchar2 items and return the internal pk of that record which is a NUMBER for each record. I am struggling to get the syntax right to pass an array of type VARCHAR_ARRAY to the simple sql query in the cursor and return the variable of type NUMBER_ARRAY. the Error is on line 8,42 i.e FROM table_name WHERE column_name IN VARCHAR_ARRAY which was passed to the function. Please help me with this error as I am learning plsql.
create or replace TYPE VARCHAR_ARRAY AS VARRAY(1000000) OF VARCHAR2(1000);
/
create or replace TYPE NUMBER_ARRAY AS VARRAY(1000000) OF NUMBER;
/
create or replace Function GET_PRODUCT_ID_ARR(V_PRODUCT_NUM_ARR IN VARCHAR_ARRAY)
RETURN NUMBER_ARRAY
IS
product_id_list number_array := number_array();
CURSOR c1
IS
SELECT cat_map_id
FROM mn_cat_map WHERE product_num IN (V_PRODUCT_NUM_ARR) and catalog_type = 'INT';
v_output NUMBER;
BEGIN
OPEN c1;
LOOP
fetch c1 into product_id_list;
EXIT WHEN c1%notfound;
product_id_list.extend;
product_id_list(product_id_list.count) := v_output;
dbms_output.put_line('Product ('||v_output ||'):'||product_id_list(v_output));
END LOOP;
Close c1;
RETURN product_id_list;
END;
/
There is two issues:
You have to cast varray to table:
CURSOR c1
IS
SELECT cat_map_id
FROM mn_cat_map
WHERE product_num IN (select column_value from table(V_PRODUCT_NUM_ARR))
and catalog_type = 'INT';
Add bulk collect after fetch:
LOOP
fetch c1 bulk collect into product_id_list limit 100;
EXIT WHEN c1%notfound;
product_id_list.extend;
product_id_list(product_id_list.count) := v_output;
dbms_output.put_line('Product ('||v_output ||'):'||product_id_list(v_output));
END LOOP;
If you write limit 100, each loop will put 100 records in product_id_list. You can omit limit clause, in this case you will get all records in one fetch.
EDIT
How to see results:
declare
myarray varchar_array;
my_num_array number_array;
begin
myarray := varchar_array();
myarray.extend(2);
myarray(1) := '151043';
myarray(2) := '2895';
my_num_array := GET_PRODUCT_ID_ARR(myarray);
for i in 1 .. my_num_array.count loop
dbms_output.put_line(my_num_array(i));
end loop;
end;
/
What #William is said is quiet true. VARRAY(1000000) is not recommended. Inplace you can create a type of table. However if i follow what you have done, there seems some mistakes in your code. Please see below how you can do it.
Tables Preparation:
create table mn_cat_map(cat_map_id number,
product_num varchar2(1000),
catalog_type varchar2(10));
/
INSERT INTO T541682.MN_CAT_MAP (CAT_MAP_ID, PRODUCT_NUM, CATALOG_TYPE)
VALUES (10, 'A123', 'INT');
INSERT INTO T541682.MN_CAT_MAP (CAT_MAP_ID, PRODUCT_NUM, CATALOG_TYPE)
VALUES (2, 'B121', '2Wheer');
INSERT INTO T541682.MN_CAT_MAP (CAT_MAP_ID, PRODUCT_NUM, CATALOG_TYPE)
VALUES (3, 'C645', '4Wheer');
COMMIT;
create or replace TYPE VARCHAR_ARRAY AS VARRAY(1000000) OF VARCHAR2(1000);
/
create or replace TYPE NUMBER_ARRAY AS VARRAY(1000000) OF NUMBER;
/
Code: read explainatory comments inline
CREATE OR REPLACE FUNCTION GET_PRODUCT_ID_ARR (V_PRODUCT_NUM_ARR VARCHAR_ARRAY)
RETURN NUMBER_ARRAY
IS
product_id_list number_array := number_array ();
CURSOR c1(tbl_list VARCHAR_ARRAY)
IS
SELECT cat_map_id
FROM mn_cat_map
WHERE product_num in (select column_value from table(tbl_list)) ---Checking if the item exists in the table with passed collection
AND catalog_type = 'INT';
v_output NUMBER:= 0;
BEGIN
--not opening cursor and am not looking for processing any records.
--OPEN c1(V_PRODUCT_NUM_ARR);
--passing the input varray to the cursor.
for i in c1(V_PRODUCT_NUM_ARR)
loop
v_output:=v_output + 1;
product_id_list.extend;
product_id_list(product_id_list.COUNT):= i.cat_map_id;
DBMS_OUTPUT.put_line('Product (' || v_output || '):' ||product_id_list(product_id_list.COUNT));
end loop;
RETURN product_id_list;
END;
/
Execution:
SQL> select GET_PRODUCT_ID_ARR(VARCHAR_ARRAY('A123','B121','C645')) COl1 from dual;
COL1
--------------------------------------------------------------------------------
NUMBER_ARRAY(10)
Product (1):10

Exception is not getting called in plsql

I am a beginner in plsql. The code below runs without any compilation error but the notFoundException is not getting called. Any help would be appriciated.
declare
abc exception;
notFoundException exception;
cursor c1(dd number) is select first_name from employees where salary = dd;
begin
for i in c1(&t)
loop
if(c1%rowcount!=1) then
raise abc;
elsif(c1%notfound) then
raise notFoundException;
else
dbms_output.put_line(i.first_name);
end if;
end loop;
Exception
when abc then
dbms_output.put_line('abc');
insert into messages values('too many rows exception');
when notFoundException then
dbms_output.put_line('notFoundException');
insert into messages values('Nobody with this salary : ');
end;
/
You may use the below anonymous block and try
`SET SERVEROUTPUT ON;
DECLARE
first_name_in employees.first_name%ROWTYPE;
Salary_in employees.salary%ROWTYPE;
BEGIN
Salary_in:=&Salary;
SELECT first_name
INTO first_name_in
FROM employees
WHERE salary = Salary_in;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Nobody with this salary :'||Salary_in);
INSERT
INTO messages
VALUES ('NO_DATA_FOUND exception');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('Too many with this salary :'||Salary_in);
INSERT
INTO messages
VALUES ('TOO_MANY_ROWS exception');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('select failed with error'||SUBSTR(SQLERRM,1,100))
INSERT
INTO messages
VALUES (SUBSTR(SQLERRM,1,100));
COMMIT;
END;
/`
You don't need to use cursor attributes when using FOR LOOP. You could just query the records and make decision afterwards. Here is a running example (I didn't have the employees table, so made up a stub). The convenient thing about FOR LOOP is that you don't have to worry about closing the cursor.
DECLARE
abc EXCEPTION;
notfoundexception EXCEPTION;
CURSOR c1(dd NUMBER) IS
SELECT *
FROM (SELECT MOD(rownum, 3) salary
,rownum first_name
FROM dual
CONNECT BY LEVEL < 10)
WHERE salary = dd;
v_count NUMBER := 0;
BEGIN
FOR i IN c1(2) LOOP
v_count := v_count + 1;
IF (v_count > 1) THEN
RAISE abc;
END IF;
dbms_output.put_line(i.first_name);
END LOOP;
IF (v_count = 0) THEN
RAISE notfoundexception;
END IF;
EXCEPTION
WHEN abc THEN
dbms_output.put_line('abc');
--insert into messages values('too many rows exception');
WHEN notfoundexception THEN
dbms_output.put_line('notFoundException');
--insert into messages values('Nobody with this salary : ');
END;
/
I suggest you to read about cursors in PL/SQL.
A cursor for loop will loop through every record that is retrieved in the cursor. If no data is found, execution will never proceed inside the loop, hence no data found exception will not be raised inside the loop. Your code should be like this
declare
abc exception;
notFoundException exception;
lv_first_name varchar2(240);
cursor c1(dd number) is select first_name from employees where salary = dd;
begin
open c1;
fetch c1 into lv_first_name;
if(c1%rowcount > 1) then
raise abc;
elsif(c1%notfound) then
raise notFoundException;
else
dbms_output.put_line(lv_first_name);
end if;
close c1;
Exception
when abc then
dbms_output.put_line('abc');
insert into messages values('too many rows exception');
when notFoundException then
dbms_output.put_line('notFoundException');
insert into messages values('Nobody with this salary : ');
end;

PL/SQL exceptions dont raise

I'm new to PL/SQL and I've been struggling with this problem waay too long so I thought I'll ask here:
What I want to achieve:
I want to insert a new employee into my 'emp' table using pl/sql
blocks.
I want the data to be input from the keyboard.
Then check if the data is correct using exceptions.
After that I want the user to confirm it writing 'yes' or 'no'.
What doesn't work:
Exceptions are not being raised even though I input invalid data.
As it is now it asks the user to confirm at the same time as asking for the data. I want it to ask after inputing and after checking the
correctness
My code:
DECLARE
empno NUMBER;
ename Varchar2(30);
job Varchar2(30);
mgr NUMBER;
hiredate DATE;
sal NUMBER;
comm NUMBER;
deptno NUMBER;
confirm VARCHAR2(3);
negative_number EXCEPTION;
invalid_date EXCEPTION;
BEGIN
INSERT INTO emp
VALUES (&empno, '&ename', '&job', &mgr, '&hiredate', &sal, &comm, &deptno);
IF empno < 0 OR mgr < 0 OR sal < 0 OR comm < 0 OR deptno < 0 THEN
RAISE negative_number;
ELSIF hiredate > SYSDATE THEN
RAISE invalid_date;
END IF;
IF '&confirm' = 'yes' THEN commit;
ELSE rollback;
END IF;
EXCEPTION
WHEN negative_number THEN
dbms_output.put_line('number cannot be negative');
WHEN invalid_date THEN
dbms_output.put_line('cannot be future date');
END;
Just a little modification to your present code:
DECLARE
empno NUMBER := &empno;
ename Varchar2(30) := '&ename';
job Varchar2(30) := '&job';
mgr NUMBER := &mgr;
hiredate DATE := TO_DATE('&hiredate', 'mm/dd/yyyy');
sal NUMBER := &sal;
comm NUMBER := &comm;
deptno NUMBER := &deptno;
confirm VARCHAR2(3);
BEGIN
INSERT INTO emp
VALUES (empno, ename, job, mgr, hiredate, sal, comm, deptno);
IF empno < 0 OR mgr < 0 OR sal < 0 OR comm < 0 OR deptno < 0 THEN
RAISE_APPLICATION_ERROR ('-20001', 'Number cannot be negative!');
ELSIF hiredate > SYSDATE THEN
RAISE_APPLICATION_ERROR ('-20002', 'Cannot be future date!');
END IF;
confirm := '&confirm';
IF lower(confirm) IN ('yes', 'y') THEN
commit;
ELSE
rollback;
END IF;
END;
The last part - confirm is not possible using pure PL/SQL though. What the code does is get the value of confirm at the beginning of the execution itself, along with other variables. What you should do for this is build a front-end that would control the flow of your program before issuing a DML.
DECLARE
empno NUMBER := 10;
ename Varchar2(30) := 'sinha';
job Varchar2(30) := 'ITTTT';
mgr NUMBER := 100;
hiredate DATE := TO_DATE('09/09/2014', 'mm/dd/yyyy');
sal NUMBER := 2000;
comm NUMBER := 50;
deptno NUMBER := 10;
invalid_emp exception;
invalid_date exception;
BEGIN
INSERT INTO empl
VALUES (empno, ename, job, mgr, hiredate, sal, comm, deptno);
IF empno < 0 OR mgr < 0 OR sal < 0 OR comm < 0 OR deptno < 0 THEN
RAISE invalid_emp;
ELSIF hiredate > SYSDATE THEN
RAISE invalid_date;
END IF;
exception
when invalid_emp then
dbms_output.put_line('number cannot be negative');
when invalid_date then
dbms_output.put_line('cannot be future date');
END;
this is how you can use a user defined exception as you wanted