In PL/SQL function, I am trying to write a function with following code:
CREATE OR REPLACE FUNCTION Lib_func(id number,dateToday date)
RETURN number IS retVal number(1);
myBorrower number;
myBook number;
BEGIN
SELECT P.book_id INTO myBook, P.request_id INTO myBorrower
FROM My_requests P
WHERE P.book_id = book_id AND ROWNUM <=1;
//some if condition which updates value of retVal
RETURN retVal;
END;
/
problem is that this results in error when I compile. If I remove the second thing (i.e. P.request_id INTO myBorrower) then error is removed.
Can I not get both things selected in a single query ?
The syntax for selecting multiple variables is :
SELECT P.book_id , P.request_id
INTO myBook,myBorrower
FROM My_requests P
WHERE P.book_id = book_id AND ROWNUM <=1;
Related
I had written the below trigger
create or replace trigger my_trigger
Before insert or update on table1
referencing new as new old as old
for each row
declare id number;
cursor id_cnt is
select count(*) from table2 where my_id=:new.my_id;
begin
if :new.my_id is null
then RAISE_APPLICATION_ERROR(-001,"MY_ID should nit be null");
elsif id_cnt=0 then
RAISE_APPLICATION_ERROR(-002,"not a valid id ");
else
select new_id from table2 where my_id=:new.my_id;
if lenght(new_id) <5
then
RAISE_APPLICATION_ERROR(-003,"length is very small ");
END IF;
END IF;
END my_trigger;
At if :new.my_id is null i am getting the below error
error PLS-003036 wrong number or types of argument in call to =
There are 2 conditions needs to be checked first condition i need to check my_id is null or not and second condition need to check the length of new_id before that i am checking if that my_id is already existed in table 2 before inserting into table1
You:
want to SELECT ... INTO rather than using a CURSOR
misspelt LENGTH
need to use ' for string literals and not "; and
need to use -20000 to -20999 for user-defined error numbers.
Like this:
create or replace trigger my_trigger
Before insert or update on table1
referencing new as new old as old
for each row
declare
id number;
id_cnt PLS_INTEGER;
v_new_id table2.new_id%TYPE;
begin
IF :new.my_id is null THEN
RAISE_APPLICATION_ERROR(-20001,'MY_ID should nit be null');
END IF;
select count(*)
INTO id_cnt
from table2
where my_id=:new.my_id;
if id_cnt=0 then
RAISE_APPLICATION_ERROR(-20002,'not a valid id');
else
select new_id
INTO v_new_id
from table2
where my_id=:new.my_id;
if length(v_new_id) < 5 then
RAISE_APPLICATION_ERROR(-20003,'length is very small');
END IF;
END IF;
END my_trigger;
/
db<>fiddle here
I want to find if p_param2 is in subquery then do some operations according to this result. This subquery returns more than 1 row.
if p_param1 = 1
and p_param2 in (select code from x_table where code is not null) then
--..Some operations..
end if;
But I get PLS-00405 error. How can write this code effectively?
You need to get the needed value before IF..THEN statement within a seperate SQL query, while the current case is not possible. Try such a method which uses COUNT() aggregation without need of exception handling :
DECLARE
p_param1 ...
p_param2 ...
p_exists INT;
BEGIN
SELECT SIGN( COUNT(*) )
INTO p_exists
FROM x_table
WHERE code IS NOT NULL
AND code = p_param2;
IF p_param1 = 1 AND p_exists = 1 THEN
-- some operations
END IF;
END;
/
Declare a var v_dummy number. Then:
begin
select 1
into v_dummy
from x_table
where code = p_param2;
exception
when no_data_found then
v_dummy := 0;
end;
if p_param1 = 1 and v_dummy = 1 then
.
.
.
end if;
If x_table.code can contain duplicate values, you have to decide what to do when more than one occurrence of p_param2 is found.
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;
/
Table 1
ID
----------
1
2
3
4
5
Table 2
ID Desc
------------------------------
A1 Apple
A2 Pear
A3 Orange
I am trying to create a Function in Oracle, so that it add the prefix 'A' in Table 1, and after that I want to look up in Table 2 to get the DESC returned. It has to be a function.
Thank you!!!
You may use the following for creation of such a function :
Create or Replace Function Get_Fruit( i_id table2.description%type )
Return table2.description%type Is
o_desc table2.description%type;
Begin
for c in ( select description from table2 where id = 'A'||to_char(i_id) )
loop
o_desc := c.description;
end loop;
return o_desc;
End;
where
no need to include exception handling, because of using cursor
instead of select into clause.
using table_name.col_name%type for declaration of data types for
arguments or variables makes the related data type of the columns
dynamic. i.e. those would be able to depend on the data type of the
related columns.
the reserved keywords such as desc can not be used as column names
of tables, unless they're expressed in double quotes ("desc")
To call that function, the following might be preferred :
SQL> set serveroutput on
SQL> declare
2 i_id pls_integer := 1;
3 o_fruit varchar2(55);
4 begin
5 o_fruit := get_fruit( i_id );
6 dbms_output.put_line( o_fruit );
7 end;
8 /
Apple
PL/SQL procedure successfully completed
I am not sure with your question- Are you trying to achieve something like this:-
CREATE OR REPLACE FUNCTION Replace_Value
(
input_ID IN VARCHAR2
) RETURN VARCHAR2
AS
v_ID varchar(2);
BEGIN
begin
SELECT distinct a.ID into v_id from Table 2 a where a.ID in (select 'A'||b.id from table1 b where b.id=input_ID);
exception
when others then
dbms_output.put_line(sqlcode);
end;
RETURN v_id;
END Replace_Value;
Are you trying for something like this?
CREATE OR replace FUNCTION replace_value (table_name IN VARCHAR2,
input_id IN INTEGER)
RETURN VARCHAR2
AS
v_desc VARCHAR(20);
BEGIN
SELECT descr
INTO v_desc
FROM table2
WHERE id = 'A' || input_id
AND ROWNUM = 1; -- only needed if there are multiple rows for each id.
RETURN v_desc;
END replace_value;
You may also add an exception handling for NO_DATA_FOUND or INVALID_NUMBER
The function is clearly there, because I can navigate to it using SQL Developer and it compiles all fine, but when I try to use the function with or without "call", it throws:
Error(36,24): PLS-00222: no function with name 'x' exists in this
scope
This is how the function looks like:
create or replace function testfunction
(
somevalue in varchar2
)
return varchar2
AS
cursor testcursor IS
select column1, column2 from table1 t
where t.column1 = somevalue;
testcursorrec testcursor %rowtype;
messaget VARCHAR2(500);
begin
open testcursor ;
fetch testcursor into testcursorrec ;
close testcursor ;
messaget := testcursor.column1;
return messaget ;
end;
This is how I'm calling it:
messaget := testfunction(somevalue);
where both messageT and somevalue are declared as varchar2 type.
Are cursors not allowed inside function or something like that?
the error would be messaget := testcursor.column1; as the cursor is closed by then (you should just use testcursorrec.column2.
you're code isn't checking for no rows, nor duplicate rows. you can simplify this to
create or replace function testfunction
(
somevalue in table1.column1%type
)
return table1.column2%type
AS
messaget table1.column2%type; -- use %type where possible.
begin
select t.column2
into messaget
from table1 t
where t.column1 = somevalue
and rownum = 1;--only if you dont care if theres 2+ rows.
return messaget;
exception
when no_data_found
then
return null; -- if you want to ignore no rows.
end;