How to find rows that contain string in plsql function - sql

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

Related

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

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;

when I am trying to create a log_in function?Why I have error Error(3,10): PLS-00215: String length constraints must be in range (1 .. 32767)

I am trying to create a function to verify log_in by return 0(zero) if the login failed, or 1(one) if the login was successful by matching cust_id and Passwd as parametrars and I have two questions:
Why I get error bad bind p_cust_id?
How to return 0 when it fail?
.
create or replace function log_in
(
p_cust_id varchar2,
p_paswd varchar2
) return number
as p_all varchar2;
begin
select cust_id,passwd
into p_all
from customer
where cust_id=p_cust_id and passwd=p_paswd;
return 1;
end;
first of all, you are trying to select 2 column but into 1 variable. this can't be possible. check my fix below
select cust_id,passwd
into variable1, variable2
from customer
where cust_id=p_cust_id and passwd=p_paswd;
for your second requirement, you need to add below line before end.
EXCEPTION WHEN NO_DATA_FOUND THEN
return 0;
END;
EDIT
Your procedure can also be rewritten as
CREATE OR REPLACE FUNCTION LOG_IN
(
P_CUST_ID VARCHAR2,
P_PASWD VARCHAR2
) RETURN NUMBER
AS P_COUNT NUMBER;
BEGIN
SELECT COUNT(*)
INTO P_COUNT
FROM CUSTOMER
WHERE CUST_ID=P_CUST_ID AND PASSWD=P_PASWD;
IF (P_COUNT > 0)
RETURN 1;
END IF;
RETURN 0;
END;

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;

alternative to listagg in Oracle?

listagg is a function introduced in Oracle 11.2! now this function is bugging us allot, we are migrating from MySQL to Oracle and we have this query:
SELECT
p_id,
MAX(registered) AS registered,
listagg(MESSAGE, ' ') within GROUP (ORDER BY registered) AS MESSAGE
FROM
umm_parent_id_remarks_v m
GROUP BY
m.p_id;
is works fine in MySQL as far as we know
what bugging us is under Oracle it returns VARCAR and not CLOB as we need!
the text is huge and we do need it to be CLOB!
here is what I tried to do!
create a CLOB_T table of CLOB Type!
then create the function
create or replace
function listaggclob (t in clob_t)
return clob
as
ret clob := '';
i number;
begin
i := t.first;
while i is not null loop
if ret is not null then
ret := ret || ' ';
end if;
ret := ret || t(i);
i := t.next(i);
end loop;
return ret;
end;
now if I run it:
SELECT
p_id,
MAX(registered) AS registered,
listaggclob(cast(collect (MESSAGE) as clob_t)) MESSAGE
FROM
umm_parent_id_remarks_v m
GROUP BY
m.p_id;
I get
ORA-22814: attribute or element value is larger than specified in type
is there any solution for it?
thanks you
Use collect or write your own aggregation function.
WM_CONCAT worked for me.
SELECT replace(WMSYS.WM_CONCAT(myTable.name), ',', ';')
FROM myTable
GROUP BY myTable.id
I wrapped it with a "replace" to specify a different item separator (';') from the one used by WM_CONCAT (',').
Use xmlAgg, example is shown below:
SELECT RTRIM(XMLAGG(XMLELEMENT(E,colname,',').EXTRACT('//text()') ORDER BY colname).GetClobVal(),',') AS LIST
FROM tablename;
This will return clob value and so no need to create custom function.
You can solve the ORA-22814 error by using MULTISET instead of COLLECT:
SELECT
p_id,
MAX(registered) AS registered,
listaggclob(cast(multiset(
select MESSAGE
from umm_parent_id_remarks_v
where umm_parent_id_remarks_v.p_id = m.p_id
) as clob_t)) MESSAGE
FROM
umm_parent_id_remarks_v m
GROUP BY
m.p_id;
You might want to look at user-defined aggregate functions.
Differnt string aggregation techniques are shown here. They include an example for user-defined aggregate functions.
-- Creating Clobe Type --
CREATE OR REPLACE TYPE "MSCONCATIMPL_CLOB" AS OBJECT (
resultstring CLOB,
delimiter VARCHAR2(10),
STATIC FUNCTION odciaggregateinitialize ( io_srccontext IN OUT msconcatimpl_clob ) RETURN NUMBER,
MEMBER FUNCTION odciaggregateiterate (
self IN OUT msconcatimpl_clob,
value IN CLOB
) RETURN NUMBER,
MEMBER FUNCTION odciaggregateterminate (
self IN msconcatimpl_clob,
o_returnvalue OUT CLOB,
i_flags IN NUMBER
) RETURN NUMBER,
MEMBER FUNCTION odciaggregatemerge (
self IN OUT msconcatimpl_clob,
i_ctx2 IN msconcatimpl_clob
) RETURN NUMBER
);
/
-- Creating Clobe Type Body --
CREATE OR REPLACE TYPE BODY "MSCONCATIMPL_CLOB" IS
STATIC FUNCTION odciaggregateinitialize ( io_srccontext IN OUT msconcatimpl_clob ) RETURN NUMBER
IS
BEGIN
io_srccontext := msconcatimpl_clob(
NULL,
NULL
);
io_srccontext.delimiter := ' ';
RETURN odciconst.success;
END odciaggregateinitialize;
MEMBER FUNCTION odciaggregateiterate (
self IN OUT msconcatimpl_clob,
value IN CLOB
) RETURN NUMBER
IS
BEGIN
IF
value IS NOT NULL
THEN
IF
self.resultstring IS NULL
THEN
self.resultstring := self.resultstring || value;
ELSE
self.resultstring := self.resultstring
|| self.delimiter
|| value;
END IF;
END IF;
RETURN odciconst.success;
END odciaggregateiterate;
MEMBER FUNCTION odciaggregateterminate (
self IN msconcatimpl_clob,
o_returnvalue OUT CLOB,
i_flags IN NUMBER
) RETURN NUMBER
IS
BEGIN
o_returnvalue := self.resultstring;
RETURN odciconst.success;
END odciaggregateterminate;
MEMBER FUNCTION odciaggregatemerge (
self IN OUT msconcatimpl_clob,
i_ctx2 IN msconcatimpl_clob
) RETURN NUMBER
IS
BEGIN
IF
self.resultstring IS NULL
AND
i_ctx2.resultstring IS NOT NULL
THEN
self.resultstring := i_ctx2.resultstring;
ELSIF
self.resultstring IS NOT NULL
AND
i_ctx2.resultstring IS NOT NULL
THEN
self.resultstring := self.resultstring
|| self.delimiter
|| i_ctx2.resultstring;
END IF;
RETURN odciconst.success;
END odciaggregatemerge;
END;
/
-- Creating Clobe Function --
CREATE OR REPLACE FUNCTION ms_concat_clob ( input VARCHAR2 ) RETURN CLOB
PARALLEL_ENABLE
AGGREGATE USING msconcatimpl_clob;
/

Help with "Expression as an assignment target" error

simple question here, I am writing a function, but I was having trouble setting up my first if statement, my attempt is below, but I keep getting "Expression can not be used as an assignment target" error on the lines "Type := CE;" and "Type :=UG;" Im sure there is a quick fix to this...... anyone know?
CREATE OR REPLACE FUNCTION SCHEMA1."FUNCTION1" ( Id IN VARCHAR2,
term IN VARCHAR2,
Type IN VARCHAR2 default NULL )
RETURN VARCHAR2 IS
BEGIN
IF Type IS NULL
THEN
IF SUBSTR(term,5,6) = 'Q'
THEN
Type := 'CE';
ELSE
Type := 'UG';
END IF;
END IF;
........
Declare a holding variable for use within the function?
CREATE OR REPLACE FUNCTION SCHEMA1."FUNCTION1" ( Id IN VARCHAR2,
term IN VARCHAR2,
Type IN VARCHAR2 default NULL )
RETURN
VARCHAR2
IS
iType VARCHAR2;
BEGIN
iType := Type;
IF iType IS NULL
THEN
IF SUBSTR(term,5,6) = 'Q'
THEN
iType := 'CE';
ELSE
iType := 'UG';
END IF;
END IF;
........
Looks to me like you're passing 'Type' in as an argument and then trying to assign to it. Is your intent to RETURN 'CE'/'UG' based on Term? If so, introduce a new variable or change Type := to RETURN.