SQL: Function select column into variable - sql

I need to select two columns in two variables how can i do it, here the code
CREATE OR REPLACE FUNCTION checkUser(pUserName VARCHAR2, pCountry VARCHAR2)
RETURN NUMBER
IS
vUsername VARCHAR2(100);
vCountry VARCHAR2(100);
BEGIN
SELECT Person.Username INTO vUsername
FROM Person
WHERE Person.Username = pUserName;
EXCEPTION WHEN NO_DATA_FOUND THEN
vUsername := NULL;
SELECT Person.Country INTO vCountry
FROM Person
WHERE Person.Country = pCountry;
EXCEPTION WHEN NO_DATA_FOUND THEN
vCountry := NULL;
IF vUsername IS NULL OR vCountry IS NULL THEN
RETURN False;
ELSE
RETURN True;
END IF;
END checkUser;
Can i do that? I am new in SQL.

Based on what you are trying to do, the following code will give you the desired result. Note that RETURN NUMBER you are using is not right if you need to return strings 'True' or 'False' .
CREATE OR replace FUNCTION Checkuser(pusername VARCHAR2,
pcountry VARCHAR2)
RETURN VARCHAR2
IS
v_count NUMBER(10);
BEGIN
SELECT Count(1)
INTO v_count
FROM person p
WHERE p.username = pusername
AND p.country = pcountry;
IF v_count = 0 THEN
RETURN 'False';
ELSE
RETURN 'True';
END IF;
END checkuser;

Selecting more than a single column is not much more complicated than what you are doing at the moment :
SELECT p.Username,p.Country INTO vUsername, vCountry
FROM Person p
WHERE p.Username = pUserName AND p.Country = pCountry;
Just separate the columns with ',' after the SELECT and after the INTO.
Off topic, you need to make sure you don't have multiple records corresponding to your argument username and country otherwise you will have an error attempting to store a list of data in scalar variables.

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;

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;

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;