Can I have a function within a SELECT query? - sql

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;

Related

Passing Multiple Values To PL/SQL Input

I have an Oracle package which contains a function. This function has 3 inputs. I need to pass multiple values to each input. I could automate a process which runs it multiple times with each combination of variables but I would like to only make one call to the database.
Simplified Code
declare
ln_ret number;
begin
ln_ret := dbo.pkg_rpa.mis_run_script (
'%2020%',
'111','222','333','444',
'1234','2345','6192','1204'
);
dbms_output.put_line('ln_ret=' || t.t (ln_ret));
end;
CREATE OR REPLACE
package dbo.pkg_rpa IS
function mis_run_script (
p_input_dt in varchar2,
p_hospital_id in varchar2,
p_procedure_code in varchar2) RETURN number;
end PKG_RPA;
/
CREATE OR REPLACE
PACKAGE BODY dbo.pkg_rpa IS
function mis_run_claim_assessment_script (
p_input_dt in varchar2,
p_hospital_id in varchar2,
p_procedure_code in varchar2
)
Begin
for i in (select table_name from user_tables where lower(table_name) = 'temp_rpa') loop
execute immediate 'drop table temp_rpa';
end loop;
execute immediate ' create table temp_rpa as select distinct ci.claim_id, count(ci.receipt_id) as count_receipts,
sum(ci.billed_amount) as total_billed_amount, count(*) as claim_items
from claim_item ci left join claim_header ch on ch.claim_id = ci.claim_id
left join cd_hos ho on ho.hospital_id = ci.hospital_id
left join claim_type_header cl on cl.claim_id = ci.claim_id
where cl.claim_status is null and ch.deleted_flag is null
and ch.input_dt like p_input_dt
and ci.hospital_id in (p_hospital_id)
and (ci.claim_id, NVL(ci.claim_item_id,0)) in (select claim_id, NVL(claim_item_id,0) from cd_roc_claim_item
where procedure_code in (p_procedure_code))
and (ci.claim_id, NVL(ci.claim_item_id,0)) not in (select claim_id, NVL(claim_item_id,0) from cd_roc_claim_item
where procedure_code not in (p_procedure_code))
group by ci.claim_id
having sum(case when ci.service_type_id is null then 1 end) = 1)';
End;
end mis_run_script;
end PKG_RPA;
/
Pass it with quoted string (Q'<delimeter><your_actual_string><delimeter>') as follows:
begin
ln_ret := dbo.pkg_rpa.mis_run_script (
'%2020%',
Q'#'111','222','333','444'#',
Q'#'1234','2345','6192','1204'#'
);
dbms_output.put_line('ln_ret=' || t.t (ln_ret));
end;
What you could do is using an associative array as input type. Instead of varchar2, use dbms_sql.varchar2a as date type for the 2nd and 3rd arguments.
But if the arguments are related to each other, let's say
p_hospital_id '111' belongs to procedure code '1234'
p_hospital_id '222' belongs to procedure code '2345'
etc.
I think you would want to create a custom record type, create a table type of the record type and use that as an parameter.
Your arguments become p_hospital_ids in dbms_sql.varchar2a in both the package specification and the package body.
In you code, you would have to loop over it and instead of dropping the table and recreate it each time, you drop it once at the start and add data within the loop;
truncate table; --alternative drop and create
for i in 1 .. p_hospital_ids.count loop
insert into temp_rpa
select <columns>
from claim_item ci
......
and ci.hospital_id = p_hospital_ids[i]
end loop
You may want to refer to the below example which is taken from Oracle Website. Hope it helps.
CREATE OR REPLACE TYPE nt_type IS TABLE OF NUMBER;
/
CREATE OR REPLACE PROCEDURE print_nt (nt nt_type) AUTHID DEFINER IS
i NUMBER;
BEGIN
i := nt.FIRST;
IF i IS NULL THEN
DBMS_OUTPUT.PUT_LINE('nt is empty');
ELSE
WHILE i IS NOT NULL LOOP
DBMS_OUTPUT.PUT('nt.(' || i || ') = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(nt(i)), 'NULL'));
i := nt.NEXT(i);
END LOOP;
END IF;
DBMS_OUTPUT.PUT_LINE('---');
END print_nt;
/
DECLARE
nt nt_type := nt_type(); -- nested table variable initialized to empty
BEGIN
print_nt(nt);
nt := nt_type(90, 9, 29, 58);
print_nt(nt);
END;
/
You don't need dynamic SQL at all.
CREATE OR REPLACE TYPE NUMBER_TABLE_TYPE AS TABLE OF NUMBER;
CREATE OR REPLACE TYPE VARCHAR_TABLE_TYPE AS TABLE OF VARCHAR2(1000);
function mis_run_claim_assessment_script (
p_input_dt in varchar2,
p_hospital_id in NUMBER_TABLE_TYPE, -- why on earth do you put numbers as strings?
p_procedure_code in VARCHAR_TABLE_TYPE
) RETURN ??? AS
INSERT INTO temp_rpa (...)
SELECT ...
FROM ...
WHERE ch.input_dt like p_input_dt
AND ci.hospital_id MEMBER OF p_hospital_id
AND procedure_code MEMBER OF p_procedure_code ;
RETURN ???
END;
ln_ret := mis_run_claim_assessment_script(
'%2020%',
NUMBER_TABLE_TYPE(111, 222, 333, 444),
VARCHAR_TABLE_TYPE('not','clear','in','your','question')
);

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;

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

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;