Function object is invalid - oracle

I was executing query in Oracle Application Express and it was fine. Until I run my application, it gives me error
Error in PLSQL code raised during plug-in processing.
ORA-06550: line 4, column 1: PLS-00905: object
PURCHASEORDER.ACLSTUDENT_CUSTOM_AUTH is invalid ORA-06550: line 4,
column 1: PL/SQL: Statement ignored
and this is my sql
create or replace FUNCTION aclstudent_custom_auth (
p_username IN VARCHAR2(50),
p_password IN VARCHAR2(20))
RETURN boolean IS
valid boolean;
BEGIN
FOR c1 IN (SELECT 1 FROM students
WHERE upper(student_userid) = upper(p_username)
AND upper(student_last_name) = upper(p_password))
LOOP
valid := TRUE;
RETURN valid;
END LOOP;
valid := FALSE;
RETURN valid;
END;

Declaration of input parameters of the function is without length.
CREATE OR REPLACE FUNCTION aclstudent_custom_auth (
p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN boolean IS
valid boolean;
BEGIN
FOR c1 IN (SELECT 1 FROM students
WHERE upper(student_userid) = upper(p_username)
AND upper(student_last_name) = upper(p_password))
LOOP
valid := TRUE;
RETURN valid;
END LOOP;
valid := FALSE;
RETURN valid;
END;
This must work better.

As Massie says, don't specify length in your arguments. Also, as hinted by Lalit, your use of a return variable as well as two RETURN statements is superfluous. You should either just RETURN the required BOOLEAN value in one of two places or set the variable and have one RETURN at the end of the function. I'd go with the first approach as your code will be more concise.
Incidentally, I don't like using loops to check for the existence of one record, but that's by the by.
CREATE OR REPLACE FUNCTION aclstudent_custom_auth(p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN BOOLEAN IS
BEGIN
FOR c1 IN (SELECT 1
FROM students
WHERE upper(student_userid) = upper(p_username)
AND upper(student_last_name) = upper(p_password)) LOOP
RETURN TRUE;
END LOOP;
RETURN FALSE;
END;
OR
CREATE OR REPLACE FUNCTION aclstudent_custom_auth(p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN BOOLEAN IS
valid BOOLEAN;
BEGIN
FOR c1 IN (SELECT 1
FROM students
WHERE upper(student_userid) = upper(p_username)
AND upper(student_last_name) = upper(p_password)) LOOP
valid := TRUE;
END LOOP;
valid := FALSE;
RETURN valid;
END;

Related

oracle function not displaying results

I am very new to this so it might sound basic, however i want create a function that takes two input parameter , (a primary key and a numeric value) and does a calculation to compare if the input numeric value (v_priceWantToInsert) is greater than maximum value in the column of the table and returns the result as true or false.
here is the code :
CREATE OR REPLACE FUNCTION PRICE_CHECK(v_productID IN VARCHAR2, v_priceWantToInsert in NUMBER)
RETURN VARCHAR2
IS
RETURN BOOLEAN AS
v_Bool BOOLEAN;
v_MAXPRICE NUMBER;
BEGIN
SELECT
MAX(B.BIDPRICE) INTO v_MAXPRICE
FROM
PRICEBID B
WHERE B.PRODUCTID = v_productID;
IF (v_MAXPRICE > v_priceWantToInsert) THEN
v_Bool := FALSE;
ELSE
v_Bool := TRUE;
END IF;
END PRICE_CHECK;
DECLARE
var1 VARCHAR2(100);
BEGIN
var1 := case when PRICE_CHECK('P00001',45) then 'true' else 'false' end;
DBMS_OUTPUT.PUT_LINE('It is: ' || var1);
END;
however my code is showing an error that object is invalid AND Usually a PL/SQL compilation error.I am open to any solution as long as it gives me a true or false value.
There are some moments I see in the code:
Missing string's length in DECLARE part. Oracle requires to specify variable's length when it is a "stringy" type, like VARCHAR or CHAR. Limit is 32767:
var1 VARCHAR2(100); -- might be up to 32767
In the function you are using variable v_MAXPRICE which is not defined. It must be done between IS and BEGIN parts of the function's defintion. I think this is how it should look like:
IS
v_MAXPRICE number;
BEGIN
There is another moment you have in your code after you've updated the question
RETURN VARCHAR2
IS
RETURN BOOLEAN AS
v_Bool BOOLEAN;
v_MAXPRICE NUMBER;
Having 2 returns is wrong, replace it with
RETURN BOOLEAN
IS
v_Bool BOOLEAN;
v_MAXPRICE NUMBER;
and since it is a function and has to return something you need to add
return v_bool
after "end if"
I thnk the last part is the anonimous block
first of all, your function returns boolean into var1 which is defined as a varchar2. This is wrong as Oracle can't convert booleans to string and it needs help with that.
try that out:
var1 := case when PRICE_CHECK('P00001',45) then 'true' else 'false' end;

How to count rows from two columns?

I try to create the function login that takes customer number(pnr) and password from same table. Its fine to create function but test crashes with following eror:
ORA-00904: "P_PASSWD": invalid identifier
create or replace function logga_in(
p_pnr bankkund.pnr%type,
p_passwd bankkund.passwd%type
)
return number
as
v_resultat number(1);
begin
select count(pnr) into v_resultat
from bankkund
where p_pnr = pnr
and p_passwd = passwd;
return 1;
exception
when no_data_found then
return 0;
end;
There is one other problem with your code not suggested in the comments, A count function from a select into will not raise a NO_DATA_FOUND exception. You may use an IF condition on count or do something like this, which is preferable
CREATE OR REPLACE FUNCTION logga_in (
p_pnr bankkund.pnr%TYPE,
p_passwd bankkund.passwd%TYPE
) RETURN NUMBER AS
v_resultat NUMBER(1);
BEGIN
SELECT 1 --do not use count if you wish to handle no_data_found
INTO v_resultat FROM
bankkund WHERE pnr = p_pnr AND
passwd = p_passwd
AND ROWNUM = 1; --Add this
RETURN 1;
EXCEPTION
WHEN no_data_found THEN
RETURN 0;
END;
Now, as far as calling the procedure is concerned, there are various options available including using bind variable
VARIABLE p_pnr number --use the datatype of bankkund.pnr%TYPE
VARIABLE p_passwd VARCHAR2(10) --use the datatype of bankkund.passwd
SELECT logga_in(:p_pnr,:p_passwd) FROM dual;
Or substitution variable
SELECT logga_in('&p_pnr','&p_passwd') FROM dual;
Give inputs when prompted.
Or use PL/SQL block
DECLARE
v_res INT;
v_pnr bankkund.pnr%type := 12892; --or appropriate value
p_passwd bankkund.passwd%type := some_passwd';
BEGIN
v_res := logga_in();
If v_res = 1 THEN
do_something_u_want; --call or execute appropriate action.
END IF;
END;
/

Comparing number with varchar2

I have this function and I need to compare number with varchar.
CREATE OR REPLACE FUNCTION getOdds(i_odd in varchar2, i_id in number) return number as
begin
declare odd integer;
declare i_perecentage=0;
begin
if i_odd ='SP'
then
return (0);
end if;
odd:=round(to_number((1-i_perecentage/100)*i_odd),2);
if odd<1
then
return(i_odd);
else
return(round(odd,2));
end if;
end;
end;
/
PS: I edited function and i resolve problem with comparing , now i have another situation that i dont like..
This function returns calculated percentage of i_odd. The problem is that if i pass 0 in i_percentage in results i get result with no decimal places(for example: i_odd = 3.10 and i_percentage = 0 i get odd = 3 but if I pass i_odd = 3.10 and i_percentage = 1 i get odd = 3.10 ).
Why is on i_percentage = 0 i dont get decimal places ??
If you want to validate a varchar2 field as a number in PL/SQL, typically you'd just try converting it to a number and catch the exception.
CREATE OR REPLACE FUNCTION getOdds(i_odd in varchar2, i_id in number) return number as
odd number;
BEGIN
-- if i_odd = 'SP' (or another non-number), this will throw an ORA-01722
-- exception which will be caught in the exception block, below
odd := to_number(i_odd); -- you might want a format mask here
--... now you can use "odd" as a number
EXCEPTION WHEN INVALID_NUMBER THEN
return 0;
END;
/
You can also nest a begin..end block in the middle of your code just to catch exceptions, if that works better for you:
CREATE OR REPLACE FUNCTION getOdds(i_odd in varchar2, i_id in number) return number as
odd number;
begin
begin
odd := to_number(i_odd); -- you might want a format mask here
exception when INVALID_NUMBER then
odd := 0;
end;
--... now you can use "odd" as a number
end;
/
The reason why you can't catch the invalid_number exception is because you are declaring the input parameter as a number. When you call your function, Oracle tries to convert the string to a number first (and it fails of course, before entering your code at all).
If you change the input parameter to varchar2, then the conversions to number (implicit in this case) is done inside the function, and invalid numbers can be caught and handled as you want (here I'm just returning a different string to denote the issue):
create or replace function is_odd_even(i_num in varchar2)
return varchar2
is
begin
-- conversion to number is done here
if (mod(i_num, 2) = 0) then
return 'EVEN';
else
return 'ODD';
end if;
exception
when INVALID_NUMBER or VALUE_ERROR then
-- do something meaningful
return 'INV';
end;
Usage example:
with x as (
select '1' as val from dual
union all
select 'SP' as val from dual
union all
select '2' as val from dual
)
select x.val, is_odd_even(x.val)
from x;
Output:
1 ODD
SP INV
2 EVEN
SOLUTION:
CREATE OR REPLACE FUNCTION getOdds(i_odd in varchar2, i_id in number) return varchar2 as
odd varchar2(10);
ret_value number(4);
begin
if (i_odd ='SP') or i_odd is null then
return 'SP';
else
odd :=ROUND( TO_NUMBER( ( 1 - (play_beting.get_odds_percentage(i_id) / 100 ) ) * TO_NUMBER(i_odd) ), 2);
IF(odd < 1) THEN
ret_value := TO_NUMBER(i_odd);
ELSE
ret_value := to_char(odd,'9999.00');
END IF;
END IF;
RETURN to_char(ret_value,'9999.00');
END getOdds;

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

Use of boolean in PL/SQL

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

Resources