Creating functions in sqlplus - oracle

I am creating a function in oracle sql plus, that take empno as argument and returns its salary. But its not being created, where am I going wrong?
Here is my function:
CREATE FUNCTION GETEMPSALARY (EMPNUMBER IN INTEGER) RETURN INTEGER
IS
EMPSALARY INTEGER;
BEGIN
SELECT SAL INTO EMPSALARY FROM EMP WHERE EMP.EMPNO = EMPNUMBER;
RETURN EMPSALARY;
END GETEMPSALARY;
Here is the error:
Error at line 1: PLS-00103: Encountered the symbol "(" when expecting one of the following:
. # % ; is authid as cluster order using external character
deterministic parallel_enable pipelined aggregate
result_cache
1. CREATE FUNCTION GETNAMES1 (EMPID IN INTEGER) RETURN VARCHAR(20)
2. IS
3. EMPNAME VARCHAR(50);

your missing the / at the end.
CREATE FUNCTION GETEMPSALARY (EMPNUMBER IN INTEGER) RETURN INTEGER
IS
DECLARE
EMPSALARY INTEGER;
BEGIN
SELECT SAL INTO EMPSALARY FROM EMP WHERE EMP.EMPNO = EMPNUMBER;
RETURN EMPSALARY;
END GETEMPSALARY;
/
edit:
due to your new error which is on a totally different function!
CREATE FUNCTION GETNAMES1 (EMPID IN INTEGER) RETURN VARCHAR(20)
you shouldnt specifiy a precision on returns, so put
RETURN VARCHAR2
also dont use VARCHAR, only VARCHAR2
and for statement ignored;
SQL> CREATE FUNCTION GETEMPSALARY (EMPNUMBER IN INTEGER) RETURN INTEGER
2 IS
3 EMPSALARY INTEGER;
4 BEGIN
5 SELECT SAL INTO EMPSALARY FROM EMP WHERE EMP.EMPNO = EMPNUMBER;
6 RETURN EMPSALARY;
7 END GETEMPSALARY;
8 /
Warning: Function created with compilation errors.
SQL> show errors
Errors for FUNCTION GETEMPSALARY:
LINE/COL ERROR
-------- -----------------------------------------------------------------
5/1 PL/SQL: SQL Statement ignored
5/32 PL/SQL: ORA-00942: table or view does not exist
SQL>
what is the subsequent error you see, as this error should be followed by a real error

Related

Can cursor be use in UPDATE and DELETE in Function

I have one doupt while I try to use UPDATE and DELETE method.
So starting from basic function something like
FUNCTION GET_ANSWER(p_questionId IN INT)
RETURN SYS_REFCURSOR IS
rc SYS_REFCURSOR;
/*getAnswer*/
BEGIN
OPEN rc FOR
SELECT * FROM answers WHERE AnswerID = p_questionId;
RETURN rc;
END GET_ANSWER;
While I try to use DELETE or UPDATE method I get error message
Error(3529,1): PLS-00103: Encountered the symbol "DELETE" when expecting one of the following: ( - + case mod new not null select with <an identifier> <a double-quoted delimited-identifier> <a bind variable> continue avg count current exists max min prior sql stddev sum variance execute forall merge time timestamp interval date <a string literal with character set specification> <a number> <a single-quoted SQL string> pipe <an alternatively-quoted string literal with character set specification>
Error(3530,1): PLS-00103: Encountered the symbol "RETURN"
Error(3536,1): PLS-00103: Encountered the symbol "END"
FUNCTION DELETE_ACTIVITY(p_activityId IN INT)
RETURN SYS_REFCURSOR IS
rc SYS_REFCURSOR;
BEGIN
OPEN rc FOR
DELETE FROM activities WHERE id = p_activityId;
RETURN rc;
END DELETE_ACTIVITY;
What is wrong here ? Wher did I made mistake ?
Don't do it via cursor, but simply
DELETE FROM answers WHERE AnswerID = p_questionId;
Also, make it a procedure, not a function.
As of UPDATE, well - it depends on what you want to update and how, but - generally:
update answers set
some_column = some_value
where ansewrID = p_questionId
Why a procedure and not a function:
SQL> create or replace function f_test return number is
2 begin
3 delete from test;
4 return 1;
5 end;
6 /
Function created.
SQL> select f_test from dual;
select f_test from dual
*
ERROR at line 1:
ORA-14551: cannot perform a DML operation inside a query
ORA-06512: at "SCOTT.F_TEST", line 3
SQL>
However, if a function is an autonomous transaction, you can do that, but - not recommended:
SQL> create or replace function f_test return number is
2 pragma autonomous_transaction;
3 begin
4 delete from test;
5 commit;
6 return 1;
7 end;
8 /
Function created.
SQL> select f_test from dual;
F_TEST
----------
1
SQL>
Cursors are only used for SELECT statements. You cannot open a cursor for an INSERT, UPDATE or DELETE statement.
See the documentation
An explicit cursor definition has this syntax:
CURSOR cursor_name [ parameter_list ] [ RETURN return_type ] IS
select_statement;

Error(11,10): PLS-00306: wrong number or types of arguments in call to 'CONSTRUCT'

I am new to plsql i try to run the piece of code but it is giving error and not able to debug
create or replace type final as object ( ename1 varchar2(10), sal1
NUMBER(7,2));--object
create or replace type construct is table of final; /*nested table of
object type */
create or replace function returnmore (empno1 number) /*Function to
return more*/
return construct
AS
vemp construct:=construct();
vename varchar2(10);
vsal1 NUMBER(7,2);
begin
select ENAME,sal into vename,vsal1 from emp where empno=empno1;
vemp.extend;
vemp(1):=construct(vename,vsal1);
return vemp;
end;
But gives me an error
Function SYSTEM.RETURNMORE#loacaDB
Error(11,1): PL/SQL: Statement ignored
Error(11,10): PLS-00306: wrong number or types of arguments in call to 'CONSTRUCT'
I am using oracle10gxe and sqldeveloper4.2
You can prefer using non-preserved keyword such as typ_emp instead of final which's reserved.
SQL> create or replace type typ_emp as object ( ename1 varchar2(10), sal1 number(7,2));
SQL> create or replace type construct is table of typ_emp;
and you can convert your function as below :
create or replace function returnmore( empno1 emp.empno%type )
return construct AS
vemp construct := construct();
vename varchar2(10);
vsal1 number(7, 2);
begin
select ename, sal into vename, vsal1 from emp where empno = empno1;
vemp.extend;
vemp(1) := typ_emp(vename, vsal1);
dbms_output.put_line(vemp(1).ename1);
return vemp;
end;
/
or another way to handle the same operation :
SQL> create or replace function returnmore( empno1 emp.empno%type )
return construct AS
vemp construct := construct();
v_sql varchar2(2000);
begin
v_sql := 'select typ_emp(ename, sal) from emp where empno = :v_empno1';
execute immediate v_sql bulk collect into vemp using empno1;
dbms_output.put_line(vemp(1).ename1);
return vemp;
end;
/
and test by invoking
SQL> set serveroutput on;
SQL> declare
result construct;
begin
result := returnmore( 1 ); -- 1 is just an ordinary presumed value for empno
end;
/ --> this will return the employee name as printed.
P.S. Never ever use SYSTEM user for non-administrative purposes. May be extremely harmful for your database.

Oracle function to return value from select with union

I am trying to add this function to oracle db but it keeps throwing the following errors:
10/72 PLS-00049: bad bind variable 'COMMITID'
12/90 PLS-00049: bad bind variable 'COMMITID'
14/76 PLS-00049: bad bind variable 'COMMITID'
17/16 PL/SQL: ORA-00933: SQL command not properly ended
CREATE OR REPLACE FUNCTION GetLatestProfileChangeDateTime(commitId IN NUMBER)
RETURN DATE
AS
testing DATE;
BEGIN
select max(a) as dateOfChange
INTO testing
from
(
select max(created_date) a from image_set where reference_id = :commitId and created_date is not null
union
select max(date_of_change) a from preferred_agent_info_history where commit_id = :commitId and date_of_change is not null
union
select max(date_of_change) a from commit_history where commit_id = :commitId and date_of_change is not null
)
RETURN testing;
END;
The inner select statement works fine but when I try to implement it within a function, I can't get it to accept it. I've even tried removing the parameter binding in the select statements for a starting place but it will throw different errors.
You don't need bind variables in your function; you are using the function parameter in the SQL part of the function, so you can simply refer to it by its name.
For example:
SQL> create or replace function f1(p IN number) return number is
2 retVal number;
3 begin
4 select :p * 2 into retVal from dual;
5 return retVal;
6 end;
7 /
Warning: Function created with compilation errors.
SQL> sho err
Errors for FUNCTION F1:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/12 PLS-00049: bad bind variable 'P'
The right way:
SQL> create or replace function f1(p IN number) return number is
2 retVal number;
3 begin
4 select f1.p * 2 into retVal from dual;
5 return retVal;
6 end;
7 /
Function created.
SQL> select f1(3) from dual;
F1(3)
----------
6

BULK COLLECT INTO: 'identifier' must be declared

i am new to PLSQL and making a couple of exercises using Bulk SQL.
I have the following package:
/*Update a commision with a new factor*/
FUNCTION commision_pct_update(p_job_id jobs.job_id%type, p_factor NUMBER) RETURN NUMBER;
and the following body:
FUNCTION commision_pct_update(p_job_id jobs.job_id%type, p_factor NUMBER) RETURN NUMBER AS
BEGIN
SELECT job_id BULK COLLECT INTO v_employees_tab FROM employees;
FORALL i IN v_employees_tab.FIRST..v_employees_tab.LAST
UPDATE employees SET commission_pct = (commission_pct * p_factor)
WHERE commission_pct is not null AND job_id = p_job_id;
RETURN SQL%ROWCOUNT;
END commision_pct_update;
I receive the following error in my Messages Log. (I'm using Oracle SQL Developer).
Error(43,37): PLS-00201: identifier 'V_EMPLOYEES_TAB' must be declared
I don't know where or how to declare the identifier in the function.
EDIT:
You need to define your variable (v_employees_tab) before the BEGIN, and indicate its type... for example:
FUNCTION commision_pct_update(p_job_id jobs.job_id%type, p_factor NUMBER) RETURN NUMBER AS
TYPE employees_type IS TABLE OF employees%ROWTYPE INDEX BY PLS_INTEGER;
v_employees_tab employees_type;
BEGIN
[...]
That's a sample type of course, choose your correct one

ORA-04091 mutating table error when calling a function from a procedure

I have a task:
Write a procedure to update salary (salary * % of increment) in emp table based on grade. Use function to get increment
This is my procedure:
CREATE OR REPLACE
PROCEDURE sal_incre
IS
CURSOR c_cur
IS
SELECT * FROM emp_task;
BEGIN
UPDATE emp_task SET sal = sal + sal_incr(grade_id);
FOR rec IN c_cur
LOOP
dbms_output.put_line(rec.empno||','||rec.ename||','||rec.sal);
END LOOP;
END;
This is my function code:
CREATE OR REPLACE
FUNCTION sal_incr(
p_grade NUMBER)
RETURN
IS
v_inc NUMBER;
BEGIN
SELECT raise_percent
INTO v_inc
FROM sal_inc
WHERE grade_id IN
(SELECT grade_id FROM emp_task WHERE grade_id = p_grade
);
RETURN v_inc;
COMMIT;
END;
When I call the procedure I'm getting:
ORA-04091: table SCOTT.EMP_TASK is mutating, trigger/function may not see it
ORA-06512: at "SCOTT.SAL_INCR", line 8
ORA-06512: at "SCOTT.SAL_INCRE", line 6
ORA-06512: at line 2
What am I doing wrong?
Your function is referring to the same table you're using in the procedure at the point you call that function, which is what causes this error. You're updating and querying it at the same time, in a way that could cause indeterminate (or confusing) results, even though you aren't querying the column you're updating. Oracle is protecting you from yourself here.
In your function you're doing:
SELECT raise_percent
INTO v_inc
FROM sal_inc
WHERE grade_id IN
(SELECT grade_id FROM emp_task WHERE grade_id = p_grade
);
There is no need to look at the emp_task table here. Unless you've been passed an nonexistent value (which can't happen from your procedure) the subquery can only return the original p_grade argument value, so this is the same as:
SELECT raise_percent
INTO v_inc
FROM sal_inc
WHERE grade_id = p_grade;
If you do that the function no longer refers to emp_task, so it won't throw the mutating trigger/function error when it's called as part of an update.
And your function should not be issuing a COMMIT - let the calling procedure, or preferably the session that calls the procedure, decide whether the who transaction should be committed or rolled back.
Also, from the title and column name it looks like raise_percent is a percentage, so you need to use that to find the value to multiply by - you shouldn't add that percentage figure. If that gives you a value of 2 for a 2% raise, for example, you need to either do this in your procedure:
UPDATE emp_task SET sal = sal * (1 + (sal_incr(grade_id)/100));
Or more neatly have your function return 1 + (raise_percent/100) and do:
UPDATE emp_task SET sal = sal * sal_incr(grade_id);
Change the procedure like this:
create or replace
procedure sal_incre
is
cursor c_cur is
select distinct e.grade_id,e.ename,e.sal from sal_inc s
join emp_task e on e.grade_id = s.grade_id order by e.ename ;
v_incr number;
begin
for f_cur in c_cur
loop
v_incr := sal_incr(f_cur.grade_id);
update emp_task set sal = sal + v_incr;
dbms_output.put_line('Emp Name : '||f_cur.ename||','
||' Sal:'||f_cur.sal||','||' Grade: '||f_cur.grade_id);
end loop;
end;

Resources