I have a stored procedure where I am trying to take 2 input age and name
That will update the record in employee table.
But when I am compiling getting - compiled with errors
Code :
CREATE OR REPLACE PROCEDURE update_emp_age
(
v_age in number;
v_ename in varchar2(255 char);
) AS
BEGIN
UPDATE employee
SET
eage = v_age
WHERE
ename = v_ename;
ROLLBACK;
END;
Remove the size from the data types in the signature.
Use commas and not semi-colons between arguments in the signature.
Don't ROLLBACK (else your query will perform the update and then immediately ROLLBACK the change doing lots of work for no effect and potentially rolling back prior chages).
Like this:
CREATE OR REPLACE PROCEDURE update_emp_age
(
v_age in NUMBER,
v_ename in VARCHAR2
) AS
BEGIN
UPDATE employee
SET eage = v_age
WHERE ename = v_ename;
END;
/
You could also use %TYPE in the signature:
CREATE OR REPLACE PROCEDURE update_emp_age
(
v_age in EMPLOYEE.EAGE%TYPE,
v_ename in EMPLOYEE.ENAME%TYPE
) AS
BEGIN
UPDATE employee
SET eage = v_age
WHERE ename = v_ename;
END;
/
db<>fiddle here
Just started with the issue of procedures in PL/SQL Oracle and I am presenting a problem at the time of executing it, it indicates the error ORA-00984
The following is the code of the procedure I am performing
create or replace PROCEDURE P_FILEUPLOAD_XML IS
BEGIN
INSERT INTO SPRCMNT (
SPRCMNT_CMTT_CODE,
SPRCMNT_TEXT,
SPRCMNT_TEXT_NAR)
VALUES(P_CMTT_CODE,
P_TEXT,
P_TEXT_NAR);
EXCEPTION WHEN OTHERS THEN
COMMIT;
END;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error:' || SQLERRM);
DBMS_LOB.CLOSE(l_loc);
--dbms_output.put_line('P_RET_VAL:' || P_RET_VAL);
END;
This is the error when saving my procedure
PL/SQL: ORA-00984: column not allowed here
I do not know if I am missing any declaration of variables or something, as I say I am just beginning with the issue of procedures and request your help.
You can use this method to insert into your table. Where you assign the variables inside the procedure
create or replace PROCEDURE P_FILEUPLOAD_XML AS
-- Declare the Variables
P_CMTT_CODE VARCHAR2(200);
P_TEXT VARCHAR2(200);
P_TEXT_NAR VARCHAR2(200);
BEGIN
-- Set variables with a value
P_CMTT_CODE := 'VALUE 1';
P_TEXT := 'VALUE 2';
P_TEXT_NAR := 'VALUE 3';
-- Insert into table
INSERT INTO SPRCMNT
( SPRCMNT_CMTT_CODE,
SPRCMNT_TEXT,
SPRCMNT_TEXT_NAR )
VALUES
( P_CMTT_CODE,
P_TEXT,
P_TEXT_NAR );
EXCEPTION
-- Catch error and log result
WHEN OTHERS THEN
dbms_output.put_line('Error:' || SQLERRM);
END;
Or alternative pass the variables into the procedure. both will achieve the same result
create or replace PROCEDURE P_FILEUPLOAD_XML(P_CMTT_CODE VARCHAR2,P_TEXT VARCHAR2, P_TEXT_NAR VARCHAR2) AS
BEGIN
-- Insert into table
INSERT INTO SPRCMNT
( SPRCMNT_CMTT_CODE,
SPRCMNT_TEXT,
SPRCMNT_TEXT_NAR )
VALUES
( P_CMTT_CODE,
P_TEXT,
P_TEXT_NAR );
EXCEPTION
-- Catch error and log result
WHEN OTHERS THEN
dbms_output.put_line('Error:' || SQLERRM);
END;
-- How to run procedure
BEGIN
P_FILEUPLOAD_XML('VALUE1' , 'VALUE2', 'VALUE3');
END;
CREATE TABLE T1 (EMP_NAME VARCHAR2 (40));
INSERT INTO t1
VALUES ('Vinoth');
COMMIT;
CREATE TABLE T2 (EMP_NAME VARCHAR2 (40));
CREATE OR REPLACE PACKAGE TEST_PKG_V
AS
PROCEDURE P_MAIN (p_status OUT VARCHAR2);
TYPE T1_TYPE IS RECORD (EMP_NAME T1.EMP_NAME%TYPE);
TYPE T1_TBL IS TABLE OF T1_TYPE;
END TEST_PKG_V;
/
CREATE OR REPLACE PACKAGE BODY TEST_PKG_V
AS
PROCEDURE P_MAIN (p_status OUT VARCHAR2)
IS
LV_T1_TBL T1_TBL := T1_TBL ();
CURSOR T1_CUR
IS
(SELECT EMP_NAME FROM t1);
BEGIN
OPEN T1_CUR;
LOOP
FETCH T1_CUR
BULK COLLECT INTO LV_T1_TBL
LIMIT 10000;
INSERT INTO t2 (EMP_NAME)
SELECT EMP_NAME FROM TABLE (LV_T1_TBL);
EXIT WHEN T1_CUR%NOTFOUND;
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
p_status := 'FAIL';
RAISE;
END P_MAIN;
END TEST_PKG_V;
/
DECLARE
VAR VARCHAR2(4000);
BEGIN
TEST_PKG_V.P_MAIN(VAR);
END;
While executing the procedure throws the ORA-00902: invalid datatype.
If I comment out the insert statement inside the procedure, it is running perfectly fine. What is the problem here and help me with resolution.
For you to be able to do it like that, the types have to be created outside of your package. Here is the corrected version. Downside is, types beeing created, if you alter your table to change the type of the column, you might forget to modify the type.
CREATE TYPE T1_TYPE AS OBJECT ( EMP_NAME VARCHAR2(40));
CREATE TYPE T1_TBL AS TABLE OF T1_TYPE;
CREATE OR REPLACE PACKAGE TEST_PKG_V
AS
PROCEDURE P_MAIN (p_status OUT VARCHAR2);
END TEST_PKG_V;
/
CREATE OR REPLACE PACKAGE BODY TEST_PKG_V
AS
PROCEDURE P_MAIN (p_status OUT VARCHAR2)
IS
LV_T1_TBL T1_TBL;
CURSOR T1_CUR
IS
(SELECT T1_TYPE(EMP_NAME) EMP_NAME FROM t1);
BEGIN
OPEN T1_CUR;
LOOP
FETCH T1_CUR
BULK COLLECT INTO LV_T1_TBL
LIMIT 10000;
INSERT INTO t2 (EMP_NAME)
SELECT EMP_NAME FROM TABLE (LV_T1_TBL);
EXIT WHEN T1_CUR%NOTFOUND;
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
p_status := 'FAIL';
RAISE;
END P_MAIN;
END TEST_PKG_V;
/
If you want your types to be generic and adapt to your table, I think you will have to do it something like that :
CREATE OR REPLACE PACKAGE TEST_PKG_V AS
TYPE T1_TYPE IS RECORD (EMP_NAME T1.EMP_NAME%TYPE);
TYPE T1_TBL IS TABLE OF T1_TYPE;
PROCEDURE P_MAIN (p_status OUT VARCHAR2);
FUNCTION GET_T1 RETURN T1_TBL PIPELINED;
END TEST_PKG_V;
/
CREATE OR REPLACE PACKAGE BODY TEST_PKG_V IS
CURSOR T1_CUR IS (SELECT EMP_NAME FROM t1);
FUNCTION GET_T1 RETURN T1_TBL PIPELINED IS
LV_T1_TBL T1_TBL;
BEGIN
OPEN T1_CUR;
FETCH T1_CUR BULK COLLECT INTO LV_T1_TBL;
CLOSE T1_CUR;
FOR IDX IN 1..LV_T1_TBL.COUNT LOOP
PIPE ROW (LV_T1_TBL(IDX));
END LOOP;
END;
PROCEDURE P_MAIN (p_status OUT VARCHAR2) IS
BEGIN
INSERT INTO t2 (EMP_NAME) SELECT EMP_NAME FROM TABLE (GET_T1);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
p_status := 'FAIL';
RAISE;
END P_MAIN;
END TEST_PKG_V;
/
alternatively, you could do it by iterating directly on your cursor :
CREATE OR REPLACE PACKAGE TEST_PKG_V AS
TYPE T1_TYPE IS RECORD (EMP_NAME T1.EMP_NAME%TYPE);
TYPE T1_TBL IS TABLE OF T1_TYPE;
PROCEDURE P_MAIN (p_status OUT VARCHAR2);
END TEST_PKG_V;
/
CREATE OR REPLACE PACKAGE BODY TEST_PKG_V IS
PROCEDURE P_MAIN (p_status OUT VARCHAR2) IS
CURSOR T1_CUR IS (SELECT EMP_NAME FROM t1);
BEGIN
FOR CURRENT_ROW IN T1_CUR LOOP
INSERT INTO t2 (EMP_NAME) VALUES (CURRENT_ROW.EMP_NAME);
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
p_status := 'FAIL';
RAISE;
END P_MAIN;
END TEST_PKG_V;
/
I have some problem in execute immediate insert statement exception part.
I have a table query_tb that contains two columns (DEPT and SOURCE_VALUE)
The column contains data in below
CLERK
select a.empno,a.ename,a.job,a.mgr,a.hiredate,b.deptno,b.dname,b.loc
from emp a,dept b where a.deptno=b.deptno and a.empno= '#V_GCIF#'
SALESMAN
select e.empno,e.ename,e.job,d.deptno,d.dname,d.loc from emp e,dept
d where e.deptno=d.deptno and e.empno= '#V_GCIF#'
MANAGER
select a.empno,a.ename,a.job,b.deptno,b.dname,b.loc from employee
a,department b where a.deptno=b.deptno and a.empno= '#V_GCIF#'
ADMIN
select a.empno,a.ename,a.job,b.deptno,b.dname,b.loc from employee
a,department b where a.deptno=b.deptno and a.empno= '#V_GCIF#'
If I pass the correct empno which is keep on the emp table it runs fine. But if I pass the incorrect empno (no data) then exception part not working.
create or replace
PROCEDURE test_emp_sp(
p_id IN VARCHAR2)
AS
CURSOR rec
IS
SELECT dept,
source_value
FROM query_tb;
v_query VARCHAR2(1000);
BEGIN
FOR rec IN
(SELECT dept,source_value FROM query_tb
)
LOOP
IF rec.dept='CLERK' THEN
v_query :=REPLACE(rec.source_value,'#V_GCIF#',p_id);
EXECUTE IMMEDIATE 'INSERT INTO emp_tb (empno,ename,job,mgr,hiredate,deptno,dname,loc) ('||v_query|| ')';
dbms_output.put_line(v_query||' inserted');
ELSE
v_query:=REPLACE(rec.source_value,'#V_GCIF#',p_id);
EXECUTE IMMEDIATE 'INSERT INTO emp_tb (empno,ename,job,deptno,dname,loc) ('||v_query||')';
dbms_output.put_line(v_query||' inserting others');
END IF;
END LOOP;
commit;
EXCEPTION
WHEN others THEN
dbms_output.put_line('No data Found...');
END;
That's because you are not running a select command, it is an insert command (insert select) which means that if the select won't return rows it just doesn't insert anything and no error is thrown for that. You should check whether the insert command has affected any rows. The way you do that in Oracle is checking the SQL%ROWCOUNT immediate after the execution, if it turns to be 0 then you do your job raising an exception. It would be something like:
DECLARE
customException EXCEPTION;
PRAGMA EXCEPTION_INIT( customException, -20001 );
....
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO emp_tb (empno,ename,job,mgr,hiredate,deptno,dname,loc)
('||v_query|| ')';
IF (SQL%ROWCOUNT) = 0 then
raise_application_error( -20001, 'This is a custom error' );
end if;
EXCEPTION
WHEN customException THEN
dbms_output.put_line('No data Found...');
END;
It's a long time without programming in Oracle PLSql So somethings there on the provided code may not compile but it is all there look into it in the internet and you will be good.
Exception does not work because there is no exception.
If SELECT returns NULL then 0 rows will be INSERT.
Example:
insert into t1(c1)
select 100 from dual where 1=0;
Result: 0 rows inserted.
insert into ... select from..
will not raise a no_data_found exception. It will just insert 0 records.
To test if you have inserted any records you can use SQL%ROWCOUNT after the insert statement.
execute immedate 'INSERT...;
if SQL%ROWCOUNT=0
then
dbms_output.put_line('no records inserted');
else
...
end if;
Also you might want to consider changing #V_GCIF# into something that can be used as a bind varaiable such as :P_ID.
You can skip the replace statement and change the execute immediate into something like:
execute immediate 'INSERT INTO ...'||v_query
using p_id;
This will bind the value of p_id to the :p_id in the statement.
The very basic thing here is to capture the error appropriately so that you can able to track back. Here i have put loggers and EXCEPTION handlers jsut to check the error. Also i have put a RAISE_APPLICATION_ERROR. Did some modifications too in the snipet. Hope it helps.
PS: Have not checked for the syntax as i dont have workspace now with me.
CREATE OR REPLACE
PROCEDURE test_emp_sp(
p_id IN VARCHAR2)
AS
--Not needed
-- CURSOR rec
-- IS
-- SELECT dept,
-- source_value
-- FROM query_tb;
--Not needed
v_query VARCHAR2(1000);
BEGIN
FOR rec IN
(SELECT dept,source_value FROM query_tb
)
LOOP
IF rec.dept='CLERK' THEN
v_query :=REPLACE(rec.source_value,'#V_GCIF#',p_id);
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO emp_tb (empno,ename,job,mgr,hiredate,deptno,dname,loc) ('||v_query|| ')';
dbms_output.put_line(v_query||' inserted');
EXCEPTION WHEN OTHERS THEN
dbms_output.put_line(' Error while inserting data in emp_tab for Clerk--> '||SQLCODE||'---'||SQLERRM);
END;
ELSE
v_query:=REPLACE(rec.source_value,'#V_GCIF#',p_id);
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO emp_tb (empno,ename,job,deptno,dname,loc) ('||v_query||')';
dbms_output.put_line(v_query||' inserting others');
EXCEPTION WHEN OTHERS THEN
dbms_output.put_line(' Error while inserting data in emp_tab for other then clerk --> '||SQLCODE||'---'||SQLERRM);
END;
END IF;
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,'Error occurred in the plsql block',TRUE);
END;
/
Bellow is my procedure.
create or replace procedure my_log (action in varchar2, message in varchar2 )
is
begin
Insert into my_log_table (ACTION, MESSAGE, EVENT_DATE)
values (action, message, sysdate);
commit;
end;
/
CREATE OR REPLACE PROCEDURE "CUSTOMER_INCREMENTAL" ()
IS
err_num NUMBER;
err_msg VARCHAR2(4000);
BEGIN
my_log ('Start','My message');
INSERT INTO NDB_AML_CUSTOMER
(ID, TITLE,...)
SELECT ID, TITLE,...
FROM NDB_CUSTOMER_NEW
WHERE DATE_TIME > (SELECT RUN_DATE FROM CHECK_POINT WHERE TABLE_NAME = 'NDB_CUSTOMER_NEW');
UPDATE CHECK_POINT SET RUN_DATE = SYSDATE WHERE TABLE_NAME = 'NDB_CUSTOMER_NEW';
COMMIT;
my_log ('End','My message');
EXCEPTION
WHEN OTHERS THEN
err_num := SQLCODE;
err_msg := SQLERRM;
my_log ('Error' , errnum ||' - ' || err_msg);
END;
/
When I compile it gives the error PLS-00103: Encountered the symbol ")" when expecting one of the following: current delete exists prior. Any suggestions?
You do not need () if function or procedure has no parameters.