Basic question about PL/SQL SELECT statement, how to declare - sql

I am trying to execute the function, but :
5/5 PLS-00103: begin function pragma procedure subtype type
current
cursor delete.
How can I repair it ?
create or replace function is_valid_value(resourceToCheck in varchar2,columnToCheck in varchar2,valueToCheck in varchar2)
return varchar2 is
v_value valid_values.resourceName%type;
declare
v_resource resourceToCheck;
v_name columnToCheck;
v_value valueToCheck ;
begin
begin
Select resourceName,columnName,validValue into v_resource,v_name,v_value
from valid_values
where
resourceName =resourceToCheck
AND columnName = columnToCheck
AND validvalue = valueToCheck
AND
upper(resourceName) = upper (valuetoCheck);
exception
when no_data_found then
return 0;
end;
return 1;
end is_valid_value ;

It seems you have several syntax errors in the routine:
-- function with 3 parameters
create or replace function is_valid_value(resourceToCheck in varchar2,
columnToCheck in varchar2,
valueToCheck in varchar2)
-- returns varchar2
return varchar2
is
-- uses 3 local variables; please, note their types
v_resource valid_values.resourceName%type;
v_name valid_values.columnName%type;
v_value valid_values.validValue%type;
begin
-- if we have a single record
select resourceName,
columnName,
validValue
into v_resource,
v_name,
v_value
from valid_values
where resourceName = resourceToCheck
and columnName = columnToCheck
and validvalue = valueToCheck
and upper(resourceName) = upper(valuetoCheck);
-- we return '1' (please, remember the declaration "return varchar2")
return '1';
exception
-- When we have no records
when no_data_found then
-- we return '0' (again, we return VarChar2)
return '0';
end is_valid_value;

You don't actually need the query to retrieve values just to indicate if there is a record or not. The following query seems to satisfy the requirement and be much simpler.
This way you avoid an EXCEPTION handler; neither return value is actually an exception so this seems more 'correct'.
I would also suggest using Y/N as the return if you want a VARCHAR2. Use 1/0 if you want to use a NUMBER. Mixing them could be confusing later for maintenance.
CREATE OR REPLACE FUNCTION is_valid_value(resourcetocheck IN VARCHAR2
, columntocheck IN VARCHAR2
, valuetocheck IN VARCHAR2)
RETURN VARCHAR2
IS
func_result VARCHAR2(1);
BEGIN
-- Indicate if it is a valid result
SELECT rec_exist
INTO func_result
FROM (SELECT '1' as rec_exist
FROM valid_values
WHERE resourcename = resourcetocheck
AND columnname = columntocheck
AND validvalue = valuetocheck
AND UPPER(resourcename) = UPPER(valuetocheck)
UNION ALL
SELECT '0' FROM dual)
WHERE rec_exist = 'Y' OR rownum = 1;
-- we return '1' (please, remember - VarChar2)
RETURN func_result;
END is_valid_value;

Related

Unable to pass varchar datatype as input parameter in my SQL function

Unable to pass varchar2 datatype in my function.
Below is my code:
create
or replace function f1(i varchar2) return varchar is j varchar2(10);
begin
select
last_name into j
from
employees
where
first_name = 'I';
return j;
end
;
/
Select f1('Steven') from dual;
It is showing null value instead of returning the Name.
You need to reference your parameter without quotes in your where clause, not as 'I'.
create or replace function f1(i varchar2)
return varchar
is
j varchar2(10);
begin
select last_name
into j
from per_all_people_f
where first_name=i;
return j;
end;

How to find rows that contain string in plsql function

When i try to implement the function to find if rows contain a string.
The function always return 0.
This is my function
member function containsText (pString1 varchar2, pString2 varchar2)return integer is
checked integer;
begin
if INSTR(pString2,pString1)=0 then checked := 0;
else checked := 1 ;
end if;
return checked;
end containsText;
i implement the function like below,
containsText (table_name.column_name, 'some_string_here');
it returns 0.
2 i try to find out why it doesn't work by using the code below,
containsText('abcdefg','fg');
it returns 0 as well.
i try instr method alone, it works
instr('abcdefg','fg');
it returns 6.
i use instr in query to implement my original idea
select instr(table_name.column_name,'Great') from table_name
it works. How could i make this function working as my expect?
Try
member function containsText (pString1 varchar2, pString2 varchar2)return integer is
checked integer;
begin
if INSTR(pString1, pString2)=0 then checked := 0;
else checked := 1 ;
end if;
return checked;
end containsText;
You change in INSTR(pString1, pString2)=0
You have the arguments to INSTR reversed. Also you have a MEMBER function but do not appear to be using any features that would require this. You could use:
Oracle Setup:
CREATE TYPE test_obj AS OBJECT(
value VARCHAR2(20),
MEMBER FUNCTION checkText(
self IN OUT test_obj,
match IN VARCHAR2
) RETURN NUMBER
);
/
CREATE TYPE BODY test_obj IS
MEMBER FUNCTION checkText(
self IN OUT test_obj,
match IN VARCHAR2
) RETURN NUMBER
IS
BEGIN
RETURN LEAST( INSTR( self.value, match ), 1 );
END;
END;
/
Testing:
DECLARE
v_test test_obj := test_obj( 'abcdefgh' );
BEGIN
DBMS_OUTPUT.PUT_LINE( v_test.checkText( 'gh' ) );
DBMS_OUTPUT.PUT_LINE( v_test.checkText( 'i' ) );
END;
/
Outputs:
1
0
db<>fiddle here
You could also write it without the SELF argument and taking two strings (as you've done in the question) but there does not seem to be much point of making this a MEMBER function of a type and it could just be a global stored-function or a STATIC function of the type.
CREATE TYPE test_obj AS OBJECT(
unused_value VARCHAR2(20),
MEMBER FUNCTION checkText( -- could be STATIC FUNCTION
value IN VARCHAR2,
match IN VARCHAR2
) RETURN NUMBER
);
/
CREATE TYPE BODY test_obj IS
MEMBER FUNCTION checkText( -- could be STATIC FUNCTION
value IN VARCHAR2,
match IN VARCHAR2
) RETURN NUMBER
IS
BEGIN
IF INSTR( value, match ) = 0 THEN
RETURN 0;
ELSE
RETURN 1;
END IF;
END;
END;
/
Then:
DECLARE
v_test test_obj := test_obj( 'xyz' );
BEGIN
DBMS_OUTPUT.PUT_LINE( v_test.checkText( 'abcdefgh', 'gh' ) );
DBMS_OUTPUT.PUT_LINE( v_test.checkText( 'abcdefgh', 'x' ) );
END;
/
Outputs:
1
0
db<>fiddle here

Can I have a function within a SELECT query?

Can I have a function within select statement like this?
select
myseq.nextval,
getDoctor(dbNumber,C.code,DOCCODE),
getDoctor(dbNumber,C.code,RFDOCCODE),
...
from charges c
where type='R';
Here getdoctor points to a function that checks two tables and returns a value:
create or replace function getDoctor(dbNumber IN NUMBER,code IN VARCHAR2(10),doccode IN VARCHAR2(10), OUT DOCID VARCHAR2(10))
is
begin
DOCID:= nvl((select MDOCID from NEW_PROVIDERS NP where dbNumber=NP.dbNumber and code=NP.code and doccode=NP.doccode),
select MDOCID from ProvidersProxy P where P.originalDB=dbNumber and code=P.originalGroup and doccode=P.originalDocCode);
return DOCID;
end getDoctor;
Write this (don't forget about the "p_" prefixes):
create or replace function getDoctor(
p_dbNumber IN NUMBER,
p_code IN VARCHAR2(10),
p_doccode IN VARCHAR2(10)
) return varchar2
is
l_DOCID VARCHAR2(10);
begin
begin
select MDOCID
into l_DOCID
from NEW_PROVIDERS NP
where p_dbNumber=NP.dbNumber
and p_code=NP.code
and p_doccode=NP.doccode
;
exception
when no_data_found then
select MDOCID
into l_DOCID
from ProvidersProxy P
where P.originalDB=p_dbNumber
and p_cpcode=P.originalGroup
and p_doccode=P.originalDocCode
;
end;
return l_DOCID;
end getDoctor;
The basic signature for an Oracle SQL usable function (which is well documented everywhere), is of the form:
FUNCTION my_function (param1 datatype, param2 datatype)
RETURN datatype
IS
local_variable1 datatype;
local_variable2 datatype;
BEGIN
-- Do something awesome
return local_variable;
/* Optional Exceptions Block */
END;
So in your case (with some rewriting of the NVL()) then:
create or replace function getDoctor(p_dbNumber IN NUMBER, p_code IN VARCHAR2, p_doccode IN VARCHAR2)
return varchar2
is
DOCID VARCHAR2(10);
begin
select MDOCID into DOCID
from NEW_PROVIDERS NP
where p_dbNumber=NP.dbNumber
and p_code=NP.code
and p_doccode=NP.doccode;
return DOCID;
EXCEPTION
when no_data_found then
select MDOCID INTO DOCID
from ProvidersProxy P
where P.originalDB=p_dbNumber
and p_code=P.originalGroup
and p_doccode=P.originalDocCode;
return DOCID;
end getDoctor;

PL SQL Function - How to call

I have a function in PL/SQL as follows (being used in Oracle APEX):
create or replace FUNCTION User_Levels(result OUT VARCHAR2)
RETURN VARCHAR2 IS
v_user_types employee.user_type%TYPE;
BEGIN
SELECT user_type
INTO v_user_types
FROM Employee
WHERE upper(username) = v('APP_USER');
IF v_user_types = 1
THEN
result := 'TRUE';
ELSE
result := 'FALSE';
END IF;
END User_Levels;​
How can I call this just to see its current output in normal SQL i.e. does it evaluate to True or False at the time it is run.
Do I really need the OUT parameter called result?
From SQL*Plus:
var result varchar2(10);
var rc varchar2(10);
exec :rc := user_levels(:result);
print rc
print result
However, your function is invalid because you have no return clause. Since the only thing you can return is result, having that as both an out parameter and the return value is redundant. Which you keep depends on how you want to use it, but I'd suggest a function is more flexible and appropriate here.
create or replace FUNCTION User_Levels
RETURN VARCHAR2 IS
v_user_types employee.user_type%TYPE;
BEGIN
SELECT user_type
INTO v_user_types
FROM Employee
WHERE upper(username) = v('APP_USER');
IF v_user_types = 1 THEN
RETURN 'TRUE';
ELSE
RETURN 'FALSE';
END IF;
END User_Levels;​
/
... assuming v('APP_USER') does something sensible. You can then just do:
select user_levels from dual;
Should work. Typically, you would create a variable (like v_user_types) and return that (p_result). Also, you need to make sure that your v('APP_USER') is also uppercase.
Additionally, you can not run this from a SQL*PLUS or any command prompt as v('APP_USER') is application variable; therefore, you have to test this on an APEX page.
create or replace FUNCTION User_Levels(p_result OUT VARCHAR2)
RETURN VARCHAR2 IS
v_user_types employee.user_type%TYPE;
p_result VARCHAR2(10);
BEGIN
SELECT user_type
INTO v_user_types
FROM Employee
WHERE upper(username) = v('APP_USER');
IF (v_user_types = 1) THEN
p_result := 'TRUE';
ELSE
p_result := 'FALSE';
END IF;
RETURN p_result;
END User_Levels;​

PLS-00103 Oracle stored procedure error

I am new to stored procedures.
I am trying to run stored procedure and getting these errors:
I am getting PLS-00103: Encountered the symbol "SELECT" when expecting one of the following: begin function pragma procedure...
PLS-00103: Encountered the symbol "RETURN" when expecting one of the following: * & = - + < / > at in is mod remainder not rem then...
I have tried searching for what causes these errors and for examples similar to this, but results were not sufficient. Any clues as to why these errors are happening?
here is the code:
CREATE OR REPLACE PROCEDURE LIST_ACTIONS_CHECK_ADD
(
LISTNAME IN VARCHAR2
) AS
BEGIN
DECLARE CNT NUMBER;
SELECT COUNT(LIST_NAME) INTO CNT FROM LISTS_MASTER WHERE LIST_NAME = LISTNAME;
IF (CNT > 0)
RETURN 1
ELSE
RETURN 0
END IF;
END LIST_ACTIONS_CHECK_ADD;
New Code:
CREATE OR REPLACE PROCEDURE LIST_ACTIONS_CHECK_ADD
(
P_LISTNAME IN VARCHAR2
)
AS
L_CNT NUMBER;
BEGIN
SELECT COUNT(LIST_NAME)
INTO L_CNT
FROM LISTS_MASTER
WHERE LIST_NAME = P_LISTNAME;
IF (L_CNT > 0)
RETURN 1;
ELSE
RETURN 0;
END IF;
END LIST_ACTIONS_CHECK_ADD;
The skeleton of a stored procedure declaration is
CREATE OR REPLACE PROCEDURE procedure_name( <<parameters>> )
AS
<<variable declarations>>
BEGIN
<<code>>
END procedure_name;
In the code you posted,
You put the BEGIN before the variable declarations
You have an extraneous DECLARE-- you would only use that if you are declaring a PL/SQL block that doesn't involve a CREATE.
You are missing semicolons after your RETURN statements.
A procedure cannot return a value. If you want to return either a 1 or a 0, you probably want a function, not a procedure. If you need a procedure, you can declare an OUT parameter.
You are missing the THEN after the IF
It sounds like you want something like
CREATE OR REPLACE FUNCTION LIST_ACTIONS_CHECK_ADD
(
LISTNAME IN VARCHAR2
)
RETURN NUMBER
AS
CNT NUMBER;
BEGIN
SELECT COUNT(LIST_NAME)
INTO CNT
FROM LISTS_MASTER
WHERE LIST_NAME = LISTNAME;
IF (CNT > 0)
THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END LIST_ACTIONS_CHECK_ADD;
Note that as a general matter, you are generally better off using some sort of naming convention to ensure that parameters and local variables do not share the name of a column. Trying to figure out whether LISTNAME is a parameter or a column name and what the difference between LIST_NAME and LISTNAME is will generally confuse future programmers. Personally, I use a p_ prefix for parameters and a l_ prefix for local variables. I would also suggested using anchored types-- lists_master.list_name%type if that is what is being passed in
CREATE OR REPLACE FUNCTION LIST_ACTIONS_CHECK_ADD
(
P_LIST_NAME IN lists_master.list_name%type
)
RETURN NUMBER
AS
L_CNT NUMBER;
BEGIN
SELECT COUNT(LIST_NAME)
INTO L_CNT
FROM LISTS_MASTER
WHERE LIST_NAME = P_LIST_NAME;
IF (L_CNT > 0)
THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END LIST_ACTIONS_CHECK_ADD;
(Correction #1) You cannot return a value in a procedure; LIST_ACTIONS_CHECK_ADD should be dropped and declared as a function in order to return a NUMBER
(Correction #2) You need to move the declaration of CNT as follows (see below)
(Correction #3) You need semicolons on the return statements:
(Correction #4) You need a THEN after IF (CNT > 0) (see below):
DROP PROCEDURE LIST_ACTIONS_CHECK_ADD;
CREATE OR REPLACE FUNCTION LIST_ACTIONS_CHECK_ADD
(
LISTNAME IN VARCHAR2
)
RETURN NUMBER AS
CNT NUMBER;
BEGIN
SELECT COUNT(LIST_NAME) INTO CNT FROM LISTS_MASTER WHERE LIST_NAME = LISTNAME;
IF (CNT > 0) THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END LIST_ACTIONS_CHECK_ADD;
This Can be executed from SQLPLUS as:
SET SERVEROUTPUT ON SIZE 100000;
DECLARE
V_RESULT NUMBER;
BEGIN
V_RESULT := LIST_ACTIONS_CHECK_ADD('X');
DBMS_OUTPUT.PUT_LINE('RESULT: ' || V_RESULT);
END;