Why while loop in plsql not working? - oracle

Noob question, why this:
CREATE OR REPLACE FUNCTION Get_tipo_aula ( nm IN VARCHAR2, n IN NUMBER)
RETURN VARCHAR2
IS
type array_t is varray(3) of varchar2(11);
array array_t := array_t('Conferenze','Laboratorio','Aula');
Aula varchar2(11);
i NUMBER;
BEGIN
i:=1;
SELECT tipo_modulo
INTO Aula
FROM Modulo
WHERE Nome_modulo = nm;
--
WHILE Aula <> array_t(i)
LOOP
i := i+1;
END LOOP;
RETURN array_t(1 + mod(i+n-1,3));
END;
/
is giving me those errors :
15/1 PL/SQL: Statement ignored
15/12 PLS-00306: wrong number or types of arguments in call to '!='
19/1 PL/SQL: Statement ignored
19/8 PLS-00382: expression is of wrong type
knowing that the first select has the purpouse of loading into aula a string of the same value of the array above ? My desired result is to obtain from the while the index of first occurrence in the array of the string contained in Aula and then return the value of the array shifted of some position.
Ex :
input value ... , 2
selection result Aula
Expected result of the while : i = 3
Expected returned value : array_t(1+mod(3+2-1,3)) = array_t(2) = 'Laboratorio')
I don't know what kind of syntax mistake I'm doing honestly.

It's a simple typo. You need to use the variable name in your code, not the type. So, correct these two lines ...
WHILE Aula <> array(i)
....
RETURN array(1 + mod(i+n-1,3));
... and your code will compile.
By the way, array is a really poor name for a variable because it is so easy to confuse with a data type. Even with toy code it pays to use clear names. Even l_array would be an improvement.

Related

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;
/

PLSQL pipelined function to return a list

I'm trying to create a function to get a list of values from my database. After some researches I found that I need to use the PIPELINE function and I found some examples. I did my function but I somehow got 2 errors that I don't understand.
Here's my code :
CREATE OR REPLACE TYPE LISTE_VALUES AS TABLE OF VARCHAR2(2000);
/
CREATE OR REPLACE FUNCTION F_GET_VAL(
PI_1 IN VARCHAR2,
PI_2 IN NUMBER,
PI_3 IN VARCHAR2)
RETURN LISTE_VALUES PIPELINED
IS
W_ROW_COUNT NUMBER := 0;
BEGIN
FOR CUR IN (SELECT VALUE FROM TABLE
WHERE ...
...
)
LOOP
PIPE ROW (CUR);
W_ROUNT_COUNT := W_ROW_COUNT + 1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('There were '
|| W_ROW_COUNT
|| ' rows selected' );
END F_GET_VAL;
/
And These are the errors I get :
[Error] PLS-00382 : PLS-00382: expression is of wrong type (at the
line : PIPE ROW (CUR);)
[Error] PLS-00201 : PLS-00201: identifier 'W_ROUNT_COUNT' must be
declared
(at the line : W_ROUNT_COUNT := W_ROW_COUNT + 1;)
For the first error I triple checked and VALUE in my table has a type VARCHAR2(2000), exactly as I declared my type at the beginning (a table of VARCHAR2(2000)).
And for the second, I don't understand because I declared the variable W_ROW_COUNT in my IS statement.
If someone could help me it would be nice !
Thanks
A PIPE ROW can be created for a single row and not the cursor's name variable, which contains the entire recordset.
Just use
PIPE ROW ( cur.value );
instead of PIPE ROW ( cur );
You may also store the query output into a collection and then pipe each element.
Regarding the error due to W_ROW_COUNT, it is a typo. You have wrongly used it as W_ROUNT_COUNT while adding it.
Demo

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

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.

Array not working correctly

I have a function that takes in 1 parameter, abc(parameter1 IN varchar2)
In the parameter I will be taking in a string that is comma delimited:
E.g Abc('1,2,a')
Type vartype is varray(10) of varchar2(50);
X1 vartype:= vartype (parameter1);
For X in X1.count loop
Dbms_output.put_line(x1(X));
End loop;
The DBMS Output gives me
1,2,a
Instead of
1
2
A
Is there anyway I can solve this?
For my understanding your function parameter will be single value.
If you are mentioned varray, you should give format like ('1','2','a','b')
For example :-
declare
Type vartype is varray(10) of varchar2(50);
X1 vartype:=vartype ('1','2','a','b');
begin
For X in 1..X1.count loop
Dbms_output.put_line(x1(x));
End loop;
end;
/
Above query will help you to understand concepts of Varray
You are passing a varchar2 variable to the varray and it's considered the first paramter; so your array contains only one element (the content of parameter1). You must split the string into substring before passing to the varray.
Here is an extract from Oracle documentation
DECLARE TYPE ProjectList IS VARRAY(50) OF VARCHAR2(16);
accounting_projects ProjectList;
BEGIN
accounting_projects := ProjectList('Expense Report', 'Outsourcing', 'Auditing');
END;
For splitting a string into substring you can check some solutions here

Oracle using the like comparison taken from function in value

I am trying to create a simple function that takes in 3 parameters, 2 numbers and a string. I have written the function but am not getting the expected results from a simple select statement when using the LIKE comparison for the string.
The select from the function below returns no rows when executed with the string input value set to ebts, but if I run this as a standalone select state it returns 2 rows which what I would expect. Have used dbms output to determine if whitespace were being passed but all looks OK.
CREATE OR REPLACE FUNCTION OPC_OP.sitezone_exists
(in_site_id IN NUMBER, in_zone_id IN NUMBER, in_mod VARCHAR2)
RETURN NUMBER
IS
v_count_rec NUMBER;
v_return NUMBER;
v_mod VARCHAR2(4) := in_mod;
BEGIN
SELECT COUNT(*)
INTO v_count_rec
FROM AW_ACTIVE_ALARMS
WHERE AW_ACTIVE_ALARMS.site_id = in_site_id
AND AW_ACTIVE_ALARMS.zone_id = in_zone_id
AND AW_ACTIVE_ALARMS.module LIKE 'v_mod%';
IF v_count_rec > 0
THEN
DBMS_OUTPUT.PUT_LINE('count'||v_count_rec||'=========='||v_mod||'=============');
v_return:= 1;
RETURN (v_return);
ELSE
DBMS_OUTPUT.PUT_LINE('count'||v_count_rec||'=========='||v_mod||'=============');
v_return:= 0;
RETURN (v_return);
END IF;
END sitezone_exists;
When passing in values 12, 12, ebts the output displayed is:
count 0 ==========ebts=============
RetVal = 0
If I run the same select subtituting only passing in the above values the query returns 2 rows - I have removed the like clause of the function and it then returns 2 rows, any idea why the like part of clause is failing to match with rows.
You are trying to match a string literal with this:
AND AW_ACTIVE_ALARMS.module LIKE 'v_mod%';
Change it to:
AND AW_ACTIVE_ALARMS.module LIKE v_mod||'%';
MarioAna has the right answer, IMO, but as an aside (which is too long for a comment), your function can be better written.
You're duplicating the dbms_output code, plus it's considered best practice to have a single RETURN in a function (although I would argue that more might be ok - one in the body and one per exception in the exception block...), so you could rewrite it as:
CREATE OR REPLACE FUNCTION OPC_OP.sitezone_exists
(in_site_id IN NUMBER, in_zone_id IN NUMBER, in_mod VARCHAR2)
RETURN NUMBER
IS
v_count_rec NUMBER;
v_return NUMBER;
v_mod VARCHAR2(4) := in_mod;
BEGIN
SELECT COUNT(*)
INTO v_count_rec
FROM AW_ACTIVE_ALARMS aaa
WHERE aaa.site_id = in_site_id
AND aaa.zone_id = in_zone_id
AND aaa.module LIKE v_mod||'%';
DBMS_OUTPUT.PUT_LINE('count '||v_count_rec||'=========='||v_mod||'=============');
IF v_count_rec > 0 THEN
v_return := 1;
ELSE
v_return:= 0;
END IF;
RETURN (v_return);
END sitezone_exists;
/

Resources