Add inline function with IF/ELSE clause in Oracle 12c - oracle

I have table A. If I make a query with inline function
with function f(n number) return varchar2 as
begin
return 'const string';
end;
select id, val, count, f(count) as value from A;
the result will be following:
ID VAL COUNT VALUE
---------- -------------------- ---------- ---------------
1 car 4 const string
2 building 15 const string
But if I try to make the function more complicated
with function f(n number)
return varchar2 as
begin
IF n < 5 THEN
return 'small';
ELSIF n < 50 THEN
return 'normal';
ELSE
return 'big';
END IF;
end;
select id, val, count, f(count) as value from A;
an error message appears:
with function f(n number)
*
ERROR at line 1:
ORA-00905: missing keyword
What's the problem here? Do I use right syntax for the command?

Your if statement is missing a then after the elsif condition clause, hence the missing keyword error pointing to function f. Also, after you fix this error you may get a ORA-00933: SQL command not properly ended pointing to the last semi-colon. Interestingly, the ";" does not seem to work as a terminator to the SQL statement when the PL/SQL declaration is included in the WITH clause. If we attempt to use it on its own, SQL*Plus waits for more text to be entered. So you have to end it with a / on a new line. Even in the example in SQL Reference manual uses a combination of ; and /. Here is my example I tested in PL/SQL Developer 11:
WITH
FUNCTION f(n number) return varchar2 IS
begin
if n<5 then
return 'small';
elsif (n>5 AND n<50) then
return 'medium';
else
return 'big';
end if;
end;
select f(25) from dual
/
Output:
F(25)
medium
EDIT: Also, change your AS to IS in your function definition.

Related

Why BINARY function doesnt work in SELECT statment

I am a little bit confusing in using BINARY function in PLSQL and I am not sure if this function even exist in PLSQL since I am new in PLSQL Programming
I want to return 0 or 1 depend if project number is alredy taken or not
SELECT COUNT(*) AS COUNT FROM projects WHERE BINARY CustomName = p_number;
And here is my function
FUNCTION CHECK_PROJECT_NUMBER(p_number NUMBER)
RETURN SYS_REFCURSOR IS
rc SYS_REFCURSOR;
/*CHECK IF PROJECT NUMBER IS TAKEN*/
BEGIN
OPEN rc FOR
SELECT COUNT(*) AS COUNT FROM projects WHERE BINARY CustomName = p_number;
RETURN rc;
END CHECK_PROJECT_NUMBER;
The error which I get is following
Error(869,56): PL/SQL: ORA-00920: invalid relational operator
Where did I made mistake and what I miss here ?
I don't think there is a such function (BINARY) - its a datatype.
There is also a boolean datatype but it is not used in sql (just in plsql).
Also, I do not see any need for cursor for this function, so
I would rewrite it like this:
FUNCTION CHECK_PROJECT_NUMBER(p_number NUMBER)
RETURN NUMBER IS
cnt number:=0;
BEGIN
SELECT COUNT(*) into cnt FROM projects WHERE CustomName =
p_number;
if cnt>0 then
cnt:=1;
end if;
RETURN cnt;
END CHECK_PROJECT_NUMBER;
This function will return 1 if project number is found and 0 otherwise.

How to fix "Warning: Function created with compilation errors"?

There are two tables
Customer2(CUSTID,NAME,ADDRESS,AGE,SALARY)
Order2(ORDERID, ORDERNAME,PRICE,CUSTID)
the main issue is to find total no of order made by the customer from the location
this is the plsql function of I wrote:
CREATE OR REPLACE FUNCTION totalCustomer (loc IN VARCHAR2) RETURN NUMBER IS
total number(2) := 0;
add CHAR := loc;
BEGIN
SELECT COUNT(*) FROM order2 WHERE cusid IN (SELECT cusid FROM customer2 WHERE address='add');
RETURN total;
END;
/
and this is where I'm calling the function:
DECLARE
p VARCHAR2(100);
BEGIN
p:= &p;
dbms_output.put_line (totalCustomer (p));
END;
/
I'm getting this error Warning: Function created with compilation errors.
and this one while I'm calling the function
ERROR at line 5:
ORA-06550: line 5, column 23:
PLS-00905: object SYSTEM.TOTALCUSTOMER is invalid
ORA-06550: line 5, column 1:
PL/SQL: Statement ignored
In your function:
You wrote cusid in your query but the columns are named custid in the tables.
You don't put the query result in the variable total. Your function will always return 0 the initial value you set for total.
By writing 'add' you compared the address to the literal string "add" rather than the contents of the variable add.
But there's no need to copy loc to add. You can use loc directly.
The type of number(2) for total seems a little small. Better go with number(38) (integer) instead.
The query is better written with an inner join. IN with a subquery often does not perform well.
Instead of being char the type of loc should be the type of address in customer2. You can use customer2.address%TYPE here.
CREATE OR REPLACE FUNCTION totalcustomer (loc IN customer2.address%TYPE)
RETURN number
IS
total number(38) := 0;
BEGIN
SELECT count(*) INTO total
FROM order2 o
INNER JOIN customer2 c
ON c.custid = o.custid
WHERE address = loc;
RETURN total;
END;
/
And in your anonymous block:
You declared p as char which means char(1), i.e. p can only hold one character. I'm not sure this is what you want. You can go with customer2.address%TYPE here too.
DECLARE
p customer2.address%TYPE;
BEGIN
p := &p;
dbms_output.put_line(totalcustomer(p));
END;
/

What is wrong with my PLSQL Boolean Function? [duplicate]

I have a function in PL/SQL which checks if a particular emp_id exists or not which is:
CREATE OR REPLACE FUNCTION checkEmpNo(eno numeric)
RETURN boolean IS
emp_number number;
BEGIN
SELECT emp_id INTO emp_number
FROM emp;
IF eno=emp_number
THEN
return true;
ELSE
return false;
END IF;
END checkEmpNo;
The function compiles successfully, but when I try to run it as:
DECLARE
exist boolean;
BEGIN
exist=checkEmpNo(1);
dbms_output.put_line(exist);
END;
it returns the error:
ORA-06550: line 5, column 1:
PLS-00306: wrong number or types of arguments in call to 'PUT_LINE'
ORA-06550: line 5, column 1:
PL/SQL: Statement ignored
3. BEGIN
4. exist:=checkEmpNo(1);
5. dbms_output.put_line(exist);
6. END;
EDIT:
I also tried this:
DECLARE
exist boolean:=true;
BEGIN
if(exist=checkEmpNo(1))
then
dbms_output.put_line('true');
else
dbms_output.put_line('false');
end if;
END;
And it returns the error: ORA-01422: exact fetch returns more than requested number of rows
dbms_output.put_line is not overloaded to accept a boolean argument. You can do something like
dbms_output.put_line( case when exist = true
then 'true'
else 'false'
end );
to convert the boolean into a string that you can then pass to dbms_output.
The ORA-01422 error is a completely separate issue. The function checkEmpNo includes the SELECT INTO statement
SELECT emp_id
INTO emp_number
FROM emp;
A SELECT INTO will generate an error if the query returns anything other than 1 row. In this case, if there are multiple rows in the emp table, you'll get an error. My guess is that you would want your function to do something like
CREATE OR REPLACE FUNCTION checkEmpNo(p_eno number)
RETURN boolean
IS
l_count number;
BEGIN
SELECT count(*)
INTO l_count
FROM emp
WHERE emp_id = p_eno;
IF( l_count = 0 )
THEN
RETURN false;
ELSE
RETURN true;
END IF;
END checkEmpNo;
Alternatively you can use the Oracle function diutil.bool_to_int to convert a boolean value to an integer: True -> 1, False -> 0.
dbms_output.put_line(diutil.bool_to_int(p_your_boolean));

PL/SQL recursive function return no value

I got the error message while running Oracle PL/SQL recursive function
function returned without value
Anyone knows what might be the issue?
Here's my function
FUNCTION cgic (cnt IN NUMBER)
RETURN VARCHAR2
IS
n_inv_code VARCHAR2 (20);
t_ic_chk NUMBER;
BEGIN
SELECT DBMS_RANDOM.STRING ('X', 10)
INTO n_inv_code
FROM DUAL;
select count(*) into t_ic_chk from inv_code where inv_code = n_inv_code and rownum = 1;
IF t_ic_chk = 1
THEN
n_inv_code := cgic(cnt);
ELSE
IF t_ic_chk = 0
THEN
RETURN n_inv_code;
END IF;
END IF;
END cgic;
In the event t_ic_chk = 1
you assign the value of the recursive function back to the variable: n_inv_code
however, you don't DO anything with it.
You probably want to return it.
I would recommend this code in your final section:
IF t_ic_chk = 1
THEN
n_inv_code := cgic(cnt);
END IF;
RETURN n_inv_code;
END cgic;
That's all you need:
1) if you find a row, recurse back in until you can't find one, and return that value.
2) if you can't find a row, return that value back.
3) in the event you found a row, just hand-shake the value returned back to whoever called you.
The code starting with IF t_ic_chk = 1 might be replaced with
CASE t_ic_chk
WHEN 0 THEN RETURN n_inv_code;
WHEN 1 THEN RETURN cgic(cnt);
ELSE RAISE_APPLICATION_ERROR(-20202, 'Unexpected t_ic_chk value=' || t_ic_chk);
END;
Done this way your function will either return an expected value or will raise an exception if it doesn't know what to do with the value it finds in t_ic_chk.
I do wonder why you're passing in the cnt parameter as it's never used in the procedure, except to pass it on in the recursive call.
Best of luck.

Oracle Database PLSQL Error: PLS-00103

I'm writing simple function in Oracle Database 11g that count summary salary for employee. For this we need to count days with specific status. Days is present as fields in table (Day_1, Day_2, ..., Day_30).
But i have got error during compilation:
Error(50,9): PLS-00103: Encountered the symbol ";" when expecting one of the following: :=.(#%;
Code of my package (a place where there is an error marked in code of function f2):
CREATE OR REPLACE PACKAGE pack IS
FUNCTION f1 (id IN NUMBER) return t2 PIPELINED;
FUNCTION f2 (id IN NUMBER) return number;
end pack;
/
CREATE OR REPLACE PACKAGE BODY pack IS
FUNCTION f1 (id IN NUMBER) return t2 PIPELINED IS
name VARCHAR2(50);
num number;
BEGIN
FOR i IN 1 .. id LOOP
SELECT отдел
into name
from отдел
where ид_отдела = i;
select sum(КОЛИЧЕСТВО)
into num
from Таблица_3
join Таблица_2
on Таблица_3.КТО_ПРОДАЛ = Таблица_2.ЧЛВК_ИД
where отдел = i;
PIPE ROW( t1(i, name, num) );
END LOOP;
RETURN;
END f1;
FUNCTION f2 (id IN NUMBER) return NUMBER AS
WorkingDays NUMBER := 0;
CurrentDay VARCHAR2(50);
Salary NUMBER := 120;
Total NUMBER := 0;
BEGIN
FOR i IN 1 .. 30 LOOP
EXECUTE IMMEDIATE 'SELECT День_' || i || ' FROM Таблица_2 WHERE ЧЛВК_ИД = id INTO CurrentDay';
IF WorkingDays IN ('КОМАНДИРОВКА','ВЫХОДНОЙ','ПРАЗДНИК') THEN -- <--- Here
WorkingDays := WorkingDays + 1;
END IF;
END LOOP;
Total : = Salary * WorkingDays;
RETURN Total;
END f2;
end pack;
/
How can i solve this? Maybe the problem is in the logic of the program?
That is an error on parsing, and be aware that it often does not accurately show the error itself, but where the next symbol error occurred. For example:
declare
x number;
y number;
begin
if x = 1 then
y := 1 --I forget to put on the semi-colon to end the line
end if;
end;
You'd expect an error on the missing semi-colon. What you get is:
ORA-06550: line 7, column 2:
PLS-00103: Encountered the symbol "END" when expecting one of the following:
* & = - + ; < / > at in is mod remainder not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec between || multiset member submultiset
The symbol ";" was substituted for "END" to continue.
Since in your comments you talk about changing things - perhaps to make it more readable for us (and thank you!), it may be obscuring the actual syntax glitch.
Two things I notice:
Total : = Salary * WorkingDays;
That has a space between the : and = that shouldn't be there
and:
FUNCTION f2 (id IN NUMBER) return NUMBER AS
which is normally
FUNCTION f2 (id IN NUMBER) return NUMBER IS

Resources