PL/SQL : i have a function but there is an error : "in a procedure,RETURN can not contain an expression" - oracle

Here is my code:
CREATE OR REPLACE FUNCTION customer_city_function(city_in IN VARCHAR2)
RETURN NUMBER
AS
number_cus NUMBER := 0;
CURSOR cus_cur IS
SELECT COUNT(*)
FROM customer
WHERE customer_city = city_in;
BEGIN
IF city_in IS NOT NULL THEN
OPEN cus_cur;
FETCH cus_cur INTO number_cus;
CLOSE cus_cur;
END IF;
RETURN number_cus;
END;
/
and here is warnings:
Error starting at line : 1 in command -
CREATE OR REPLACE FUNCTION customer_city_function(city_in IN VARCHAR2)
RETURN NUMBER
AS
number_cus NUMBER := 0
Error report -
SQL Command: functıon CUSTOMER_CITY_FUNCTION
Failed: Warning: executing is completed with a warning
Error starting at line : 5 in command -
CURSOR cur_cur IS
Error report -
Unknown Command
Error starting at line : 6 in command -
SELECT COUNT(*)
FROM costumer
WHERE customer_city=city_in
Error at Command Line : 8 Column : 25
Error report -
SQL Error: ORA-00904: "CITY_IN": undefined variable
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
Error starting at line : 9 in command -
BEGIN
IF city_in IS NOT NULL
THEN
OPEN cus_cur;
FETCH cus_cur INTO number_cus;
CLOSE cus_cur;
END IF;
RETURN (number_cus);
END;
Error report -
ORA-06550: row 2, column 6:
PLS-00201: 'CITY_IN' variable should been defined
ORA-06550: row 2, column 3:
PL/SQL: Statement ignored
ORA-06550: row 8, column 1:
PLS-00372: in a procedure, RETURN can not contain an expression
ORA-06550: row 8, column 1:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Where is my mistake? I can't find it, it doesn't make any sense.
(I translated this warning message from my language. I hope I did it right.)
I have just tried it in Command Window and it works. Why doensn't it work in Oracle SQL Developer sql worksheet?

There is nothing wrong with your posted code. The issue might be with your client or the way you are compiling the code.
As you have mentioned PL/SQL Developer in the tags, it might be possible that you have some extra characters in the SQL Worksheet and you are compiling the function as a script, thus the compiler finds it erroneous.
Here is a demo in SQL*Plus, and there is no error:
SQL> CREATE OR REPLACE FUNCTION customer_city_function(i_deptno IN number)
2 RETURN NUMBER
3 AS
4 number_cus NUMBER := 0;
5 CURSOR cus_cur IS
6 SELECT COUNT(*)
7 FROM emp
8 WHERE deptno=i_deptno;
9 BEGIN
10 IF i_deptno IS NOT NULL
11 THEN
12 OPEN cus_cur;
13 FETCH cus_cur INTO number_cus;
14 CLOSE cus_cur;
15 END IF;
16 RETURN number_cus;
17 END;
18 /
Function created.
SQL> sho err
No errors.
SQL> SELECT customer_city_function(10) FROM DUAL;
CUSTOMER_CITY_FUNCTION(10)
--------------------------
3
SQL>
The only difference in my code is that I have used EMP table instead of CUSTOMERS table and the input parameter is DEPTNO instead of CITY_IN. Rest everything is same and function compiles and executes without any errors.

Related

How to avoid this in PLSQL

I'm trying to create a function that looks like this
CREATE OR REPLACE FUNCTION get_sal
(dep_id IN departments.department_id%TYPE)
RETURN NUMBER IS
v_sal employees.salary%TYPE;
BEGIN
SELECT AVG(salary) INTO v_sal FROM Employees
WHERE department_id = dep_id;
RETURN v_sal;
END;
And I get an error that says
Error starting at line : 5 in command -
BEGIN
SELECT AVG(salary) INTO v_sal FROM Employees
WHERE department_id = dep_id;
RETURN v_sal;
END;
Error report -
ORA-06550: line 3, column 27:
PL/SQL: ORA-00904: "DEP_ID": invalid identifier
ORA-06550: line 2, column 5:
PL/SQL: SQL Statement ignored
ORA-06550: line 4, column 5:
PLS-00372: In a procedure, RETURN statement cannot contain an expression
ORA-06550: line 4, column 5:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
I got an example function from Oracle to see if it works but the same error appears.
There's nothing wrong with the function:
SQL> CREATE OR REPLACE FUNCTION get_sal (dep_id IN departments.department_id%TYPE)
2 RETURN NUMBER
3 IS
4 v_sal employees.salary%TYPE;
5 BEGIN
6 SELECT AVG (salary)
7 INTO v_sal
8 FROM Employees
9 WHERE department_id = dep_id;
10
11 RETURN v_sal;
12 END;
13 /
Function created.
SQL> select get_sal(10) from dual;
GET_SAL(10)
-----------
SQL>
as long as schema you're connected to contains DEPARTMENTS and EMPLOYEES tables with columns mentioned in that code. If you do not, then yes - expect errors.
As it seems you are using Sql Developer 20.4.0 as your SQL client, i guess the problem comes from the way you're compiling your SQL statement within this SQL client.
With SQL Developer, there is two ways to compile a SQL statement/execute a query. Selecting it in the editor and then click the green play button on the left as shown in the image below. The second way is to have only your statements in the editor and use the execute script button which is the second button to the right of the green play button. This one will execute all the statements in the editor.
I guess your error come from the use of the green play button while your cursor in the editor is on the statement but the statement is not fully selected or partially selected.
You can make SQL Developer complies with the behavior of Toad or have a custom behavior in this way in the SQL Developer options.

Get the first value from Oracle cursor - Calling From Java Code

I have a oracle cursor which I have created to facilitate concurrency. This is my cursor.
create or replace FUNCTION get_unlocked_records RETURN table_to_test%ROWTYPE IS
CURSOR c IS SELECT * FROM table_to_test where status_code = 5 FOR UPDATE SKIP LOCKED;
record_to_get table_to_test%ROWTYPE;
BEGIN
OPEN c;
FETCH c INTO record_to_get;
CLOSE c;
RETURN record_to_get;
END;
When I do the testing in 2 separate sql sessions using these commands,it gives the following errors.
declare
record_to_gets table_to_test%ROWTYPE;
begin
exec :record_to_gets := get_unlocked_records;
dbms_output.put_line(record_to_gets);
end;
Error
Error starting at line : 32 in command -
declare
record_to_gets table_to_test%ROWTYPE;
begin
exec :record_to_gets := get_unlocked_records;
dbms_output.put_line(record_to_gets);
end;
Error report -
ORA-06550: line 4, column 7:
PLS-00103: Encountered the symbol "" when expecting one of the following:
:= . ( # % ;
The symbol ";" was substituted for "" to continue.
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
What is the error that I am doing here ?
Since my ultimate goal is to call the function and get the result in java, how to call this function to get the first record in java ?
Thanks in advance.
EXEC[UTE] is a SQL*Plus command and prepending variable with a colon is done in SQL*Plus, but in PL/SQL EXECUTE IMMEDIATE might be used whereas that's not needed in your case, only using such an assignment without prepending the local variable is enough :
DECLARE
record_to_gets table_to_test%ROWTYPE;
BEGIN
record_to_gets := get_unlocked_records;
DBMS_OUTPUT.PUT_LINE(record_to_gets.col1);
DBMS_OUTPUT.PUT_LINE(record_to_gets.col2)
END;
/

I don't understand what is the problem in my store procedure

Create or replace PROCEDURE SSp_EmpHoursInfo
(p_EHrsInfo OUT SYS_REFCURSOR)
AS
BEGIN
OPEN p_EHrsInfo FOR
Select
a.personid, a.first_name, a.last_name,c.hoursworked,d.carecentername, c.break
from person a
join employee b on a.personid = b.empersonid
join employee_assigned_care_center c on b.empersonid = c.empersonid
join care_center d on c.empersonid = d.carecenterid
where hoursworked> 10;
END SSp_EmpHoursInfo;
Everytime I am trying to call the store procedure it is giving me this error msg:
Error starting at line : 225 in command -
BEGIN SSp_EmpHoursInfo (hoursworked> 10); END;
Error report -
ORA-06550: line 1, column 3:
PLS-00201: identifier 'HOURSWORKED' must be declared
ORA-06550: line 1, column 52:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
The problem is very obvious.
BEGIN SSp_EmpHoursInfo (hoursworked> 10); END; is not the proper way of calling it.
The procedure parameter must be the sys_refcursor.
You must use:
DECLARE
OUTPUT_CUR SYS_REFCURSOR;
BEGIN
SSp_EmpHoursInfo (OUTPUT_CUR );
-- USE CURSOR ACCORDINGLY
END;
/

Oracle procedure compiling successfully but show errors

Using Oracle SQL Developer I created a simple procedure. The procedure compiles successfully, but when I type the command:
execute CMPPROJECTPROCSELECT();
BEGIN CMPPROJECTPROCSELECT(); END;
I get the following errors:
Error starting at line : 1 in command -
execute CMPPROJECTPROCSELECT()
Error report -
ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'CMPPROJECTPROCSELECT'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Error starting at line : 2 in command -
BEGIN CMPPROJECTPROCSELECT(); END;
Error report -
ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'CMPPROJECTPROCSELECT'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Please help me to solve this. I know it's a small error. Also I have specified the data types, declarations of names correctly.
My procedure code is
CREATE OR REPLACE PROCEDURE CMPPROJECTPROCSELECT(
p_projectname IN VARCHAR2,
p_description OUT VARCHAR2)
IS
BEGIN
SELECT DESCRIPTION
INTO p_description
FROM CMPPROJECT
WHERE PROJECTNAME = p_projectname;
EXCEPTION
WHEN NO_DATA_FOUND THEN
p_description:= NULL;
COMMIT;
END CMPPROJECTPROCSELECT;
execute CMPPROJECTPROCSELECT();
BEGIN CMPPROJECTPROCSELECT();
END;
EXECUTE is SQL*Plus command.
You are not passing the required parameters to the procedure. You have declared two parameters for your procedure:
p_projectname IN VARCHAR2,
p_description OUT VARCHAR2
So, you need to declare the required parameters and then pass it to the procedure:
DECLARE
proj_desc VARCHAR2(2000);
BEGIN
CMPPROJECTPROCSELECT('project_name', proj_desc);
-- use the OUT value of proj_desc later
END;
/
On a side note, you do not need COMMIT at all. It is required to permanently commit a DML and has nothing to do with a SELECT ..INTO clause.
SELECT DESCRIPTION INTO p_description FROM CMPPROJECT WHERE PROJECTNAME = p_projectname;
EXCEPTION
WHEN NO_DATA_FOUND THEN
p_description:= NULL;
COMMIT; -- You don't need COMMIT at all
UPDATE A working demonstration:
In PL/SQL:
SQL> CREATE OR REPLACE PROCEDURE get_emp(
2 p_ename IN VARCHAR2,
3 p_job OUT VARCHAR2)
4 IS
5 BEGIN
6 SELECT job INTO p_job FROM emp WHERE ename = p_ename;
7 END;
8 /
Procedure created.
SQL> sho err
No errors.
SQL> set serveroutput on
SQL> DECLARE
2 job VARCHAR2(20);
3 BEGIN
4 get_emp('SCOTT',JOB);
5 DBMS_OUTPUT.PUT_LINE('The output is '||job);
6 END;
7 /
The output is ANALYST
PL/SQL procedure successfully completed.
In SQL*Plus:
SQL> VARIABLE JOB VARCHAR2(20);
SQL> EXECUTE get_emp('SCOTT', :JOB);
PL/SQL procedure successfully completed.
SQL> PRINT JOB;
JOB
--------------------------------
ANALYST

Oracle exception information

I'm wondering if there is a way to get a little more information about what caused the exception:
Error starting at line 5 in command:
exec ....
Error report:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at ..., line 558
ORA-06512: at ..., line 752
ORA-06512: at line 1
06502. 00000 - "PL/SQL: numeric or value error%s"
*Cause:
*Action:
I'm assuming this means I have a variable that is too small for what I tried to put in it... But why can't Oracle tell me what variable this is? It would be great for both debugging and production support people to be able to say to our client I think you have this field too big and that's what caused the error, rather than just "some value was too big and we really have no idea which one"... Using the line number would required someone who understood sql and looking at the code which is not ideal.
Why is there nothing under the Cause and Action fields?
When you try to insert into a col with data that is too large it tells you what col... I would like similar information here.
Is that possible without having to put an exception handler after every plsql line of code?
Oracle can't know what your intent is with the error information. Knowing the variable name you're storing it as or where exactly it came from isn't necessarily in the best interests of the end user or security.
For example, I can generate your error easily:
SQL> declare
2 v_tooshort varchar2(3);
3 begin
4 select 'too long' into v_tooshort from dual;
5 end;
6 /
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 4
The error already gives the line number.
Would you prefer the error give the variable name (v_tooshort)? That's not helpful to a user.
Is the right information the value, "too long"? Or the fact that it's a dummy column from the dual table? (or an actual column and table)?
Because the error arises from a select into instead of an insert statement, it's not like there's a specific database constraint the exception can identify by name.
EDIT (to address issue raised in a comment):
That's not true. You'll get the column name and lengths returned when doing an insert (as an ORA-12899), but not when doing a select into even if it's using data from a table:
SQL> create table test_length (tooshort varchar2(3));
Table created.
SQL> begin
2 insert into test_length(tooshort) values ('too long');
3 end;
4 /
begin
*
ERROR at line 1:
ORA-12899: value too large for column "MYUSER"."TEST_LENGTH"."TOOSHORT"
(actual: 8, maximum: 3)
ORA-06512: at line 2
SQL> insert into test_length(tooshort) values ('abc');
1 row created.
SQL> commit;
Commit complete.
SQL> declare
2 v_onechar varchar2(1);
3 begin
4 select tooshort into v_onechar from test_length;
5 end;
6 /
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 4
EDIT 2:
You can nest your select into into its own begin-exception-end block and raise whatever error you like (providing a unique error number and descriptive error text):
SQL> ed
Wrote file afiedt.buf
1 declare
2 v_onechar varchar2(1);
3 begin
4 select tooshort into v_onechar from test_length;
5 exception
6 when value_error then
7 RAISE_APPLICATION_ERROR(-20011, 'my variable named v_onechar is too short for the data returned from test_lengt
h.tooshort');
8* end;
SQL> /
declare
*
ERROR at line 1:
ORA-20011: my variable named v_onechar is too short for the data returned from
test_length.tooshort
ORA-06512: at line 7

Resources