Compile Error for Oracle Procedure - oracle

I have the following PL/SQL code in a script and am trying to run it in SQL*Plus:
create or replace procedure add_employee
(fname IN varchar2(20), lname IN varchar2(25), email IN varchar2(25), job IN varchar2(25))
AS
eid INTEGER := 300;
BEGIN
insert into Employees (employee_id, first_name, last_name, email, hire_date, job_id)
values (eid, fname, lname, email, job);
END add_employee;
/
I get the following error:
Errors for PROCEDURE ADD_EMPLOYEE:
LINE/COL
---------------------------------------------------------------------------
ERROR
---------------------------------------------------------------------------
1/42
PLS-00103: Encountered the symbol "(" when expecting one of the following:
:= . ) , # % default character
The symbol ":=" was substituted for "(" to continue.
I don't understand what the issue is. I have written other procedures where the opening parenthesis follows the procedure name without any problem.

You can't specify the size of strings in the procedure declaration, so it should be:
create or replace procedure add_employee
(fname IN varchar2, lname IN varchar2, email IN varchar2, job IN varchar2)
It's not a good idea to have the argument names match any table columns (email and job in this case); prefixing the parameters is common, e.g. using p_email and p_job; but should be done consistently. It often also makes it easier to follow the code even when the names don't clash - you know where the variable comes from and what its scope is.

Related

How can I deal with PL-SQL package error PLS-00103: Encountered the symbol "(" when expecting one of the following: := )

There is a similar answer for the problem I have, but it seems that this answer is for procedure issue.
I supposed to make a pl sql package which has 3 procedures inside. It's gonna be like that:
CREATE OR REPLACE PACKAGE Count_num AS
PROCEDURE count_emps(dno IN number);
PROCEDURE count_deps(empssn IN char(9));
PROCEDURE delete_deps(empssn IN char(9), dname IN varchar2(15));
END;
/
show errors
CREATE OR REPLACE PACKAGE BODY Count_num AS
PROCEDURE count_emps(dno IN number)
AS
cnt number;
BEGIN
SELECT COUNT(*) INTO cnt
WHERE Department.dnumber = Employee.dno
AND Department.dnumber = dno;
dbms_output.put_line('Number of Employee is ' || cnt);
END;
PROCEDURE count_deps(empssn IN char(9))
AS
cnt2 number;
BEGIN
SELECT COUNT(*) INTO cnt2
WHERE Dependent.essn = Employee.ssn
AND Department.essn = empssn;
dbms_output.put_line('Number of dependent is ' || cnt2);
END;
PROCEDURE delete_deps(empssn IN char(9), dname IN varchar2(15))
AS
BEGIN
DELETE *
FROM Dependent
WHERE Dependent.essn = Employee.ssn
AND Dependent.essn = empssn
AND Dependent.dependent_name = dname;
SELECT *
FROM Dependent
WHERE Dependent.essn = Employee.ssn
AND Dependent.essn = empssn
AND Dependent.dependent_name = dname;
END;
END;
/
show errors
EXEC Count_num.count_emps(5);
EXEC Count_num.count_deps('333445555');
EXEC Count_num.delete_deps('333445555', 'Alice')
show errors
count_emps counts the number of employees for a department,
count_deps counts the number of dependents for a valid employee,
delete_deps deletes a specific depdendent. It's creation query is like below:
drop table Employee cascade constraints;
commit;
create table Employee
(
fname varchar2(15),
minit varchar2(1), -- can be char
lname varchar2(15),
ssn char(9),
bdate date,
address varchar2(50),
sex varchar2(1) CHECK(Sex = 'M' or Sex = 'F'),
salary number, -- need to put check on salary
superssn char(9),
dno number DEFAULT 0,
constraint EMPPK
primary key(ssn),
constraint EMPSUPERVRFK
foreign key(superssn) references Employee(ssn)
ON DELETE SET NULL
);
drop table Department cascade constraints;
commit;
create table Department
(
dname varchar2(15) NOT NULL,
dnumber number,
mgr_ssn char(9) DEFAULT '000000000',
mgr_start_date date,
constraint DEPTPK
primary key(dnumber),
constraint DEPTMGRFK
foreign key(mgr_ssn) references Employee(ssn)
ON DELETE SET NULL
);
drop table Dependent cascade constraints;
commit;
create table Dependent
(
Essn char(9),
Dependent_name varchar2(15),
Sex varchar2(15),
Bdate date,
Relationship varchar2(15),
constraint DEPENDPK
primary key (Essn, Dependent_name),
constraint DEPENDFK
foreign key(Essn) references Employee(Ssn)
);
When I execute package queries, it gives me an error like below:
SQL> CREATE OR REPLACE PACKAGE Count_num AS
2 PROCEDURE count_emps(dno IN number);
3 PROCEDURE count_deps(empssn IN char(9));
4 PROCEDURE delete_deps(empssn IN char(9), dname IN varchar2(15));
5 END;
6 /
Warning: Package created with compilation errors.
Elapsed: 00:00:00.02
SQL> show errors
Errors for PACKAGE COUNT_NUM:
LINE/COL ERROR
-------- -----------------------------------------------------------------
3/37 PLS-00103: Encountered the symbol "(" when expecting one of the
following:
:= ) , default varying character large
The symbol ":=" was substituted for "(" to continue.
4/38 PLS-00103: Encountered the symbol "(" when expecting one of the
following:
:= ) , default varying character large
The symbol ":=" was substituted for "(" to continue.
4/60 PLS-00103: Encountered the symbol "(" when expecting one of the
LINE/COL ERROR
-------- -----------------------------------------------------------------
following:
:= . ) , # % default character
The symbol ":=" was substituted for "(" to continue.
I can't recognize what this error is, so anyone can explain what this error is, and how can I handle this issue?
Remove the length specified for the data types in the arguments.
Also, better to specify the column data type than hard-coding it.
CREATE OR REPLACE PACKAGE Count_num AS
PROCEDURE count_emps(i_dno IN employee.dno%TYPE);
PROCEDURE count_deps(i_empssn IN employee.ssn%TYPE);
PROCEDURE delete_deps(i_empssn IN employee.ssn%TYPE,
i_dname IN department.dname%TYPE
);
END;
/

Capture error using OUT parameter in Oracle's procedure

I have to create procedure to insert row into table, also I need to include am OUT parameter that would capture any errors. However when I test using anonymous block it would not work, but if I use exception in procedure it is working. It means if I add an OUT parameter and I pass values from the block it won't work.
This code works but is not what I want:
create or replace
PROCEDURE EXAM_SP
(P_FIRSTNAME IN BB_SHOPPER.FIRSTNAME%TYPE,
P_LASTNAME IN BB_SHOPPER.LASTNAME%TYPE,
P_ADDRESS IN BB_SHOPPER.ADDRESS%TYPE,
P_CITY IN BB_SHOPPER.CITY%TYPE,
P_STATE IN BB_SHOPPER.STATE%TYPE,
P_ZIP IN BB_SHOPPER.ZIPCODE%TYPE)
IS
BEGIN
INSERT INTO BB_SHOPPER (IDSHOPPER, FIRSTNAME, LASTNAME, ADDRESS, CITY,
STATE, ZIPCODE)
VALUES
(BB_SHOPPER_IDSHOPPER_SEQ.NEXTVAL,P_FIRSTNAME,P_LASTNAME,P_ADDRESS,
P_CITY, P_STATE,P_ZIP);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error Code = '||SQLCODE);
DBMS_OUTPUT.PUT_LINE('Error Message = Please check input');
END EXAM_SP;.
But in code above if I name out parameter it won't work, not sure how to do this, if I add OUT parameter to procedure and pass values:
create or replace
PROCEDURE EXAM_SP
(P_FIRSTNAME IN VARCHAR2,
P_LASTNAME IN VARCHAR2,
P_ADDRESS IN VARCHAR2,
P_CITY IN VARCHAR2,
P_STATE IN CHAR,
P_ZIP IN VARCHAR2,
P_ERROR OUT VARCHAR2)......
I will receive this error
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
If I remove parameter and use original code on the beginning it works.
Anonymous block that gets that error:
DECLARE
LV_FIRSTNAME_TXT BB_SHOPPER.FIRSTNAME%TYPE := 'FIRST';
LV_LASTNAME_TXT BB_SHOPPER.LASTNAME%TYPE := 'LAST';
LV_ADDRESS_TXT BB_SHOPPER.ADDRESS%TYPE := '8899 TAPE PARK';
LV_CITY_TXT BB_SHOPPER.CITY%TYPE := 'JACKSONVILLE';
LV_STATE_TXT BB_SHOPPER.STATE%TYPE := 'FLd';
LV_ZIP_NUMBER BB_SHOPPER.ZIPCODE%TYPE := '34567';
LV_ERROR varchar2(100);
BEGIN
EXAM_SP(LV_FIRSTNAME_TXT, LV_LASTNAME_TXT, LV_ADDRESS_TXT,
LV_CITY_TXT,LV_STATE_TXT,LV_ZIP_NUMBER);
DBMS_OUTPUT.PUT_LINE(LV_ERROR);
END;
Procedure:
create or replace
PROCEDURE EXAM_SP
(P_FIRSTNAME IN VARCHAR2,
P_LASTNAME IN VARCHAR2,
P_ADDRESS IN VARCHAR2,
P_CITY IN VARCHAR2,
P_STATE IN CHAR,
P_ZIP IN VARCHAR2,
P_ERROR OUT VARCHAR2)
IS
BEGIN
INSERT INTO BB_SHOPPER (IDSHOPPER, FIRSTNAME, LASTNAME, ADDRESS, CITY,
STATE, ZIPCODE)
VALUES
(BB_SHOPPER_IDSHOPPER_SEQ.NEXTVAL,P_FIRSTNAME,P_LASTNAME,P_ADDRESS,
P_CITY, P_STATE,P_ZIP);
EXCEPTION
WHEN OTHERS THEN
P_ERROR := SQLCODE;
/*DBMS_OUTPUT.PUT_LINE('Error Code = '||SQLCODE);
DBMS_OUTPUT.PUT_LINE('Error Message = Please check input');
P_ERROR := SQLCODE;*/
END EXAM_SP;
Error message that I am receiving:
Error report:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 6
06502. 00000 - "PL/SQL: numeric or value error%s"
I have passed variable 'FLd' to procedure parameter in order to test error capture.
Table structure:
IDSHOPPER NUMBER(4,0)
FIRSTNAME VARCHAR2(15 BYTE)
LASTNAME VARCHAR2(20 BYTE)
ADDRESS VARCHAR2(40 BYTE)
CITY VARCHAR2(20 BYTE)
STATE CHAR(2 BYTE)
ZIPCODE VARCHAR2(15 BYTE)
PHONE VARCHAR2(10 BYTE)
FAX VARCHAR2(10 BYTE)
EMAIL VARCHAR2(25 BYTE)
USERNAME VARCHAR2(8 BYTE)
PASSWORD VARCHAR2(8 BYTE)
COOKIE NUMBER(4,0)
DTENTERED DATE
PROVINCE VARCHAR2(15 BYTE)
COUNTRY VARCHAR2(15 BYTE)
...
"If I add out parameter to procedure and I pass values I will receive this error"
Alex has provided the long answer, I'm just going to make one short point: this is bad practice. Most programming languages include built-in functionality for handling exceptions. What you propose creates two architectural problems:
Programs which call your procedure have to write non-standard code to catch errors, which is just a pain for both the developers who write the calling programs and everybody else who has to understand how they work.
Your procedure doesn't hurl an exception so even though it "failed" it returns a success state to calling programs. If the developer who wrote the calling program didn't implement the special code the exception is lost and the database can be left in an invalid state.
The error stack shows:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 6
06502. 00000 - "PL/SQL: numeric or value error%s"
That stack shows, partly because it doesn't mention the procedure name, that the error is from line 6 of the anonymous block. It isn't getting as far as the call to the procedure on line 11 of that block.
The problem is that you've defined the local state variable:
LV_STATE_TXT BB_SHOPPER.STATE%TYPE := 'FLd';
using the %TYPE syntax, which is great; but as the table column is char(2), when you try to assign the three-character text literal 'Fld' to that two-character local variable it immediately errors at that point.
it is not getting as far as sending the three-character value to the procedure, so the error you're expecting from the insert doesn't appear because the insert doesn't happen either.
If you want to break it with that particular error you can either change the local variable declaration to be a fixed length instead of using %TYPE as you would normally want to:
DECLARE
LV_FIRSTNAME_TXT BB_SHOPPER.FIRSTNAME%TYPE := 'FIRST';
LV_LASTNAME_TXT BB_SHOPPER.LASTNAME%TYPE := 'LAST';
LV_ADDRESS_TXT BB_SHOPPER.ADDRESS%TYPE := '8899 TAPE PARK';
LV_CITY_TXT BB_SHOPPER.CITY%TYPE := 'JACKSONVILLE';
--LV_STATE_TXT BB_SHOPPER.STATE%TYPE := 'FLd';
-- specific length to allow invalid value to be used
LV_STATE_TXT char(3) := 'FLd';
LV_ZIP_NUMBER BB_SHOPPER.ZIPCODE%TYPE := '34567';
LV_ERROR varchar2(100);
BEGIN
EXAM_SP(LV_FIRSTNAME_TXT, LV_LASTNAME_TXT, LV_ADDRESS_TXT,
LV_CITY_TXT,LV_STATE_TXT,LV_ZIP_NUMBER,LV_ERROR);
DBMS_OUTPUT.PUT_LINE(LV_ERROR);
END;
/
-12899
PL/SQL procedure successfully completed.
Or more simply use literals directly for the IN parameters, as you are just testing the procedure at this point:
DECLARE
LV_ERROR varchar2(100);
BEGIN
EXAM_SP('FIRST', 'LAST', '8899 TAPE PARK',
'JACKSONVILLE', 'FLd', '34567', LV_ERROR);
DBMS_OUTPUT.PUT_LINE(LV_ERROR);
END;
/
-12899
PL/SQL procedure successfully completed.
You might find it more useful to return the error text, not just the number (and if you're returning the error number use a numeric formal argument type!), e.g:
...
EXCEPTION
WHEN OTHERS THEN
P_ERROR := SQLERRM;
END EXAM_SP;
/
-- same anonymous block
ORA-12899: value too large for column "MY_SCHEMA"."BB_SHOPPER"."STATE" (actual: 3, maximum: 2)
PL/SQL procedure successfully completed.
Of course, as I mentioned in a comment, it's better to let Oracle's exception handling just bubble the actual exception up to the caller - aside maybe from logging, you should only really catch exceptions you can actually handle. Notice that the error message that's passed back doesn't tell you anything about where the error occurred in the code; without the exception handler you would see the line number in the procedure that had the offending statement. And as APC points out, every caller has to look for and handle the resposne, and it would be easy to overlook. There are always exceptions (ha) of course, but this seems to be an exercise in doing things wrong.

PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: := . ( # % ;

What is wrong with my PLSQL?
CREATE OR REPLACE PROCEDURE REGISTRO_CLIENTE_TARJETA(
v_nombre IN VARCHAR2,
v_ap_paterno IN VARCHAR2,
v_ap_paterno IN VARCHAR2,
v_rfc IN VARCHAR2,
v_email IN VARCHAR2,
v_direccion IN VARCHAR2,
v_numero IN VARCHAR2,
v_num_seg IN VARCHAR2,
v_mes_exp IN VARCHAR2,
v_anio_expiracion IN VARCHAR2)
AS
BEGIN
INSERT INTO TARJETA_DE_CREDITO(TARJETA_ID, NUMERO, NUM_SEGURIDAD, MES_EXPIRACION, ANIO_EXPIRACION)
VALUES(TARJETA_CREDITO_SEQ.NEXTVAL, v_numero, v_num_seg, v_mes_exp, v_anio_expiracion)
INSERT INTO CLIENTE(CLIENTE_ID,NOMBRE, AP_PATERNO, AP_MATERNO, RFC, EMAIL, DIRECCION, TARJETA_ID)
VALUES(CLIENTE_SEQ.NEXTVAL, v_nombre, v_ap_paterno, v_ap_paterno, v_rfc, v_email, v_direccion, (SELECT LAST_NUMBER FROM ALL_SEQUENCES WHERE SEQUENCE_NAME = 'TERCERO_SEQ'))
END;
I'm getting the following errors using the show errors command:
LINE/COL ERROR
-------- -----------------------------------------------------------------
14/1 PL/SQL: SQL Statement ignored
15/88 PL/SQL: ORA-00933: SQL command not properly ended
19/3 PLS-00103: Encountered the symbol "end-of-file" when expecting
one of the following:
:= . ( # % ;
The INSERT statements must end with a semi-colon.
insert into table (columns list) values (values list);
As a good practice, always compile your code in SQL*Plus and do SHOW ERROR. Look at the line number in the error stack. Without any EXCEPTION block (or with proper exception handling), you would get the correct line number. Try to debug your code by going to the line number and verify.

Warning: Procedure created with compilation errors in oracle

CREATE TABLE:
create table customer (Name varchar2(10), Address varchar(40), Contact number);
CREATE PROCEDURE FOR INSERT:
CREATE OR REPLACE PROCEDURE SP_CUSTOMER (
p_name customer.Name%TYPE,
p_address customer.Address%TYPE,
p_contact customer.Contact%TYPE)
IS
BEGIN
INSERT INTO customer ("Name", "Address", "Contact")
VALUES (p_name, p_address, p_contact);
COMMIT;
END;
/
ERROR:
IT SHOWS: Warning: Procedure created with compilation errors.
CREATE PROCEDURE FOR SELECT:
CREATE OR REPLACE PROCEDURE SP_SELECT_CUSTOMER (
p_name customer.Name%TYPE,
p_address customer.Address%TYPE,
p_contact customer.Contact%TYPE)
IS
BEGIN
SELECT Name, Address, Contact FROM customer;
END;
/
ERROR:
IT SHOWS: Warning: Procedure created with compilation errors.
What is the problem.? How to solve it.?
Whenever you compile something in SQL*Plus and you get "compilation errors", the first thing you want to do is to SHOW ERRORS, which will tell you what actually went wrong.
Your first procedure has a problem where the column names will not match the column names from your table. Your table definition has Name, Address and Contact, but because you haven't used double-quotes, the column names will actually be NAME, ADDRESS and CONTACT - but your insert statement uses double-quotes, so it tries to insert into Name etc. Just get rid of the double-quotes, you don't need them here.
In your second procedure, you have a SELECT statement in PL/SQL, but you don't specify where to put the resulting data. You at least need an INTO clause, or perhaps do a LOOP over the resulting records.
--you need not to put the column in quotes
CREATE OR REPLACE PROCEDURE SP_CUSTOMER (
p_name customer.Name%TYPE,
p_address customer.Address%TYPE,
p_contact customer.Contact%TYPE)
IS
BEGIN
INSERT INTO customer (Name, Address, Contact)
VALUES (p_name, p_address, p_contact);
COMMIT;
END;
/
--just use a refcursor to return the resultset
CREATE OR REPLACE PROCEDURE SP_SELECT_CUSTOMER (
p_cust_details OUT SYS_REFCURSOR)
IS
BEGIN
OPEN p_cust_details for SELECT Name, Address, Contact FROM customer;
END;
/
EDIT if you want to find details based on name ,then pass an IN parameter and use it as filter condition.
CREATE OR REPLACE PROCEDURE SP_SELECT_CUSTOMER (
p_cust_name IN customer.Name%TYPE
p_cust_details OUT SYS_REFCURSOR)
IS
BEGIN
OPEN p_cust_details for SELECT Name, Address, Contact FROM customer
WHERE name=p_cust_name ;
END;
/
select * from user_errors where name='SP_SELECT_CUSTOMER'

create/declare a sequence in a stored procedure in oracle

I have a table non_employee with emp_no as the primary key and a package with a procedure to insert in to this table.
I need to be able to autoincrement the emp_no when the procedure is run. I tried creating a sequence within the procedure like this, but getting errors. please see below and advice.
CREATE OR REPLACE PACKAGE BODY WFDDEV."ERD" IS
create SEQUENCE #seq_emp_nmbr;
PROCEDURE INS_NON_EMPLOYEES
(
in_DATE_ADDED DATE,
in_EMPLOYEE_NAME VARCHAR2,
in_DEPT_ID VARCHAR2,
in_SUB_DEPARTMENT VARCHAR2,
in_LOCATION VARCHAR2,
in_WORK_TEL_NO VARCHAR2,
in_TOUR VARCHAR2,
in_REST_DAYS VARCHAR2,
in_HOME_ADDRESS VARCHAR2,
in_CITY VARCHAR2,
in_STATE VARCHAR2,
in_ZIP VARCHAR2,
in_HOME_TEL_NO VARCHAR2,
in_GENDER VARCHAR2,
in_RACE VARCHAR2,
in_DATE_OF_BIRTH DATE,
in_AGE VARCHAR2,
in_HIRE_DATE DATE,
in_UNION_AFFILIATION VARCHAR2,
in_TITLE VARCHAR2,
in_NON_EE_INDICATOR VARCHAR2
) IS
BEGIN
INSERT INTO WFDDEV.NON_EMPLOYEES
(
EMP_NO,
DATE_ADDED,
EMPLOYEE_NAME,
DEPT_ID,
SUB_DEPARTMENT,
LOCATION,
WORK_TEL_NO,
TOUR,
REST_DAYS,
HOME_ADDRESS,
CITY,
STATE,
ZIP,
HOME_TEL_NO,
GENDER,
RACE,
DATE_OF_BIRTH,
AGE,
HIRE_DATE,
UNION_AFFILIATION,
TITLE,
NON_EE_INDICATOR
)
VALUES
(
emp_no.NEXTVAL,
in_DATE_ADDED,
in_EMPLOYEE_NAME,
in_DEPT_ID,
in_SUB_DEPARTMENT,
in_LOCATION,
in_WORK_TEL_NO,
in_TOUR,
in_REST_DAYS,
in_HOME_ADDRESS,
in_CITY,
in_STATE,
in_ZIP,
in_HOME_TEL_NO,
in_GENDER,
in_RACE,
in_DATE_OF_BIRTH,
in_AGE,
in_HIRE_DATE,
in_UNION_AFFILIATION,
in_TITLE,
in_NON_EE_INDICATOR
);
END;
Im getting PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
begin end function pragma procedure subtype type
error with this...
You need to create the sequence just once outside of the package as a separate database object. Then, in the insert statement in your package body you can reference the sequence to get the next value.
Try-
EXECUTE IMMEDIATE 'CREATE SEQUENCE SEQ_NAME START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 1000000 NOCYCLE NOCACHE ORDER';
This should be inside a Procedure or Function body and not in the Declaration section i.e. this should be treated as a executable statement.
Creating a sequence using Dynamic SQL is a bad idea and I am not sure why you would want to do that. However, if you are creating a sequence dynamically then remember to drop it as well after finishing up, using
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_NAME';
This way you would atleast not run into errors (like ORA-00955) while calling the package procedure.

Resources