passing parameter to a function in a select statement dynamically - oracle

how to use dynamic value while passing the parameter in select statement.
I have a function like below ....
create or replace function get_old_GSL (p_vendor_site_id in varchar2) return varchar2
is
v_sup_gsl VARCHAR2(30);
v_ret_val VARCHAR2(30);
BEGIN
BEGIN
SELECT SUBSTR(ATTRIBUTE52,1,6)
INTO v_sup_gsl
FROM gecm_dff_ext
WHERE primary_table ='AP_SUPPLIER_SITES_ALL'
AND primary_key = p_vendor_site_id
and attribute52 is not null;
EXCEPTION
WHEN OTHERS THEN
v_sup_gsl := NULL;
END;
BEGIN
IF v_sup_gsl IS NOT NULL THEN
SELECT segment1
INTO v_ret_val
FROM ap_suppliers
WHERE segment1 = v_sup_gsl;
END IF;
EXCEPTION
WHEN OTHERS THEN
v_ret_val := NULL;
END;
return(v_ret_val);
END;
Testing the function:
---------------------
--> select GET_OLD_GSL(22758460) as xyz from dual;
--> select GET_OLD_GSL(22758529) as xyz from dual;
--> select GET_OLD_GSL(22760317) as xyz from dual;
--> select GET_OLD_GSL(22758389) as xyz from dual;
--> select GET_OLD_GSL(22759519) as xyz from dual;
Here, iam using column 'vendor_site_id' of 'ap_supplier_sites_all' table .
My requirement is passing this parameter dynamically without hard coding the parameter each time i pass.

Related

SELECT INTO variable not working in PL\SQL function

Not sure why this isn't working, when the base query (the commented out line) does return a value when I pass in the same id - when executed as a straight query outside the function.
Maybe I need to use execute immediate, but not sure why this is returning a "no data" error. I got it working with execute immediate, but interested to know what the issue is with the syntax below.
create or replace FUNCTION "FN_GET_CSP_TEMPLATE_DETAILS" (
TEMPLATE_USED_ID IN VARCHAR2 DEFAULT NULL
)
RETURN VARCHAR2 AS
v_out VARCHAR2(100);
BEGIN
dbms_output.put_line(TEMPLATE_USED_ID);
SELECT i_chronicle_id INTO v_out from TABLE_A where R_OBJECT_ID = TEMPLATE_USED_ID;
-- // this works // SELECT i_chronicle_id INTO v_out from TABLE_A where R_OBJECT_ID = 'ID_99';
dbms_output.put_line(v_out);
return v_out;
end;
So this returns a count of 1:
select count(*) from TABLE_A WHERE R_OBJECT_ID = 'ID_99';
But this returns a null value, function defined as above:
select FN_GET_CSP_TEMPLATE_DETAILS('ID_99') from dual;
This works fine:
create or replace FUNCTION "FN_GET_CSP_TEMPLATE_DETAILS" (
TEMPLATE_USED_ID IN VARCHAR2 DEFAULT NULL
)
RETURN VARCHAR2 AS
v_out VARCHAR2(100);
sql_stmt VARCHAR2(1000);
BEGIN
dbms_output.put_line(TEMPLATE_USED_ID);
sql_stmt := 'SELECT i_chronicle_id from TABLE_A where R_OBJECT_ID = :a';
EXECUTE IMMEDIATE sql_stmt into v_out using TEMPLATE_USED_ID;
dbms_output.put_line(v_out);
return v_out;
end;
Seems it only doesnt work against this production table. If I recreate a dummy table and a function against the dummy table it works.
CREATE TABLE "ANALYTICS"."TEST_CSP_FUNCTION"
( "R_OBJECT_ID" VARCHAR2(20 BYTE),
"I_CHRONICLE_ID" VARCHAR2(20 BYTE)
)
INSERT INTO TEST_CSP_FUNCTION
(R_OBJECT_ID, I_CHRONICLE_ID)
VALUES
('ID_100', 'Doc A');
INSERT INTO TEST_CSP_FUNCTION
(R_OBJECT_ID, I_CHRONICLE_ID)
VALUES
('ID_101', 'Doc B');
INSERT INTO TEST_CSP_FUNCTION
(R_OBJECT_ID, I_CHRONICLE_ID)
VALUES
('ID_102', 'Doc C');
INSERT INTO TEST_CSP_FUNCTION
(R_OBJECT_ID, I_CHRONICLE_ID)
VALUES
('ID_103', 'Doc D');
create or replace FUNCTION "FN_GET_TEST_CSP_TEMPLATE_DETAILS" (
TEMPLATE_USED_ID IN NVARCHAR2 DEFAULT NULL
)
RETURN VARCHAR2 AS
v_out VARCHAR2(100);
BEGIN
dbms_output.put_line(TEMPLATE_USED_ID);
SELECT I_CHRONICLE_ID INTO v_out FROM TEST_CSP_FUNCTION WHERE R_OBJECT_ID = TEMPLATE_USED_ID;
dbms_output.put_line(v_out);
return v_out;
end;
select FN_GET_TEST_CSP_TEMPLATE_DETAILS(N'ID_103') from dual;
returns:
Doc D
It works if row with appropriate ID exists in the table.
Demo:
SQL> select * From table_a;
R_OBJ I_CHRONICLE_ID
----- --------------
id_99 100
Function:
SQL> create or replace function fn_get_csp_template_details
2 (template_used_id in varchar2 default null)
3 return varchar2 as
4 v_out varchar2(100);
5 begin
6 dbms_output.put_line(template_used_id);
7 select i_chronicle_id
8 into v_out
9 from table_a
10 where r_object_id = template_used_id;
11 dbms_output.put_line(v_out);
12 return v_out;
13 end;
14 /
Function created.
Testing:
SQL> set serveroutput on
SQL> select fn_get_csp_template_details('id_99') as result from dual;
RESULT
--------------------------------------------------------------------------------
100
id_99
100
SQL>
If ID doesn't exist, it'll return NULL (if called from SELECT statement, as in my example):
SQL> select fn_get_csp_template_details('ABC') as result from dual;
RESULT
--------------------------------------------------------------------------------
SQL>
It'll return an exception if called elsewhere:
SQL> declare
2 l_result varchar2(100);
3 begin
4 l_result := fn_get_csp_template_Details('ABC');
5 end;
6 /
declare
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "SCOTT.FN_GET_CSP_TEMPLATE_DETAILS", line 6
ORA-06512: at line 4
SQL>
That's how it goes. So, what did you do to make it NOT work as expected?

Using count(*) to fetch more than one row in a SQL Procedure

I'm trying to return the number of rows per invoice_id using a function and procedure. Some invoice_id's have more than one row and I'm not sure how to fetch the count when I execute my procedure. As an example invoice_id(7) has just one row, but invoice_id(100) has four rows of information.
Create or replace function return_num_rows_function(invoice_id_text in varchar2)
Return varchar2
Is inv_id varchar2(20);
Begin
Select count(*)invoice_id into inv_id from invoice_line_items where invoice_id=invoice_id_text;
Return inv_id;
End;
Create or replace procedure return_num_rows (invoice_id_text in varchar2)
Is inv_id varchar(20);
line_item_desc invoice_line_items.line_item_description%type;
Begin
inv_id := return_num_rows_function(invoice_id_text);
If inv_id is not null then
Select count(*)invoice_id, line_item_description into inv_id,line_item_desc
From invoice_line_items where invoice_id = inv_id;
dbms_output.put_line('The number of rows returned:'|| inv_id);
dbms_output.put_line('Item description(s):'|| line_item_desc);
End if;
End;
set serveroutput on;
execute return_num_rows(7);
First of all do not use a string type variable for a numeric one
(invoice_id_text).
For your case it's better to use a procedure instead of called
function ( return_num_rows_function ), since you need two out
arguments returned.
A SQL Select statement cannot be used without Group By with aggegated and non-aggregated columns together ( i.e. don't use this one :
Select count(*) invoice_id, line_item_description
into inv_id,line_item_desc
From invoice_line_items
Where invoice_id = inv_id;
)
So, Try to create below procedures :
SQL> CREATE OR REPLACE Procedure
return_num_rows_proc(
i_invoice_id invoice_line_items.invoice_id%type,
inv_id out pls_integer,
line_item_desc out invoice_line_items.line_item_description%type
) Is
Begin
for c in
(
Select line_item_description
into line_item_desc
From invoice_line_items
Where invoice_id = i_invoice_id
)
loop
line_item_desc := line_item_desc||' '||c.line_item_description;
inv_id := nvl(inv_id,0) + 1;
end loop;
End;
/
SQL> CREATE OR REPLACE Procedure
return_num_rows(
i_invoice_id pls_integer
) Is
inv_id pls_integer;
line_item_desc invoice_line_items.line_item_description%type;
Begin
return_num_rows_proc(i_invoice_id,inv_id,line_item_desc);
If inv_id is not null then
dbms_output.put_line('The number of rows returned:' || inv_id);
dbms_output.put_line('Item description(s):' || line_item_desc);
End if;
End;
/
and call as in your case :
SQL> set serveroutput on;
SQL> execute return_num_rows(7);
Replace inv_id varchar2(20) with inv_id number;
and also if you want to get two outputs from procedure better to use refcursor.

converting a plsql code into a function

I have this piece of code which I want to convert into a function , and call the function in a select statement by passing vendor_site_id from ap_supplier_sites_all. so that I can get the value of vendor_number i.e segment1 of ap_suppliers . here in this piece of code , I have a login to fetch first 6 digits from the column attribute52 of DFF table gecm_dff_ext .
DECLARE
v_ret_val VARCHAR2(30);
v_sup_gsl VARCHAR2(30);
v_vendor_id NUMBER;
BEGIN
v_vendor_id := '${PO.H_VENDOR_ID}';--> vendor_id column from ap_suppliers
IF <condition> = 'Y'
THEN
BEGIN
SELECT SUBSTR(ATTRIBUTE52,1,6)
INTO v_sup_gsl
FROM gecm_dff_ext
WHERE primary_table ='AP_SUPPLIER_SITES_ALL'
AND primary_key = '${PO.H_VENDOR_SITE_ID}';--> This value should be vendor_site_id from ap_supplier_sites_all table
EXCEPTION
WHEN OTHERS THEN
v_sup_gsl := NULL;
END;
BEGIN
IF v_sup_gsl IS NOT NULL THEN
SELECT segment1
INTO v_ret_val
FROM ap_suppliers
WHERE segment1 = v_sup_gsl;
END IF;
EXCEPTION
WHEN OTHERS THEN
v_ret_val := '';
END;
END IF;
IF v_sup_gsl IS NULL THEN
BEGIN
SELECT SEGMENT1
INTO v_ret_val
FROM ap_suppliers
WHERE vendor_id=v_vendor_id;
EXCEPTION
WHEN OTHERS THEN
v_ret_val := '';
END;
END IF;
:return_value:=v_ret_val;
END;
This is a simplified example: the following SELECT returns department name for a certain department number:
SQL> select dname
2 from dept
3 where deptno = &par_deptno;
Enter value for par_deptno: 10
DNAME
--------------
ACCOUNTING
SQL>
So, how to convert it to a function? By using a proper syntax, declaring a return variable, fetching into it and - returning the result:
SQL> create or replace function f_test (par_deptno in dept.deptno%type)
2 return dept.dname%type
3 is
4 retval dept.dname%type;
5 begin
6 select dname
7 into retval
8 from dept
9 where deptno = par_deptno;
10
11 return retval;
12 exception
13 when no_data_found then
14 return null;
15 end;
16 /
Function created.
SQL> select f_test(10) from dual;
F_TEST(10)
---------------------------------------------------------------------------
ACCOUNTING
SQL> select f_test(999) from dual;
F_TEST(999)
---------------------------------------------------------------------------
SQL>
This is what you should do. It seems that you are returning the v_ret_val, so - your code might look like this:
create or replace function f_test (par_vendor_id po.h_vendor_id%type)
return ap_suppliers.segment1%type
is
v_ret_val ap_suppliers.segment1%type;
begin
if <condition> = 'Y' then
...
end if;
return v_ret_val;
end;

Display result of Stored Procedure

I creates a procedure using Toad Client that is
create or replace procedure getuid(eid_pro varchar2)is
l_value number;
begin
select uniqueid
into l_value
from enrollment
where eid=eid_pro;
end ;
When I execute it by Followings
begin
getuid('245698154');
end;
It executed successfully but result is not displayed in data grid.
Please help me in this
Turn the procedure into a function.
create or replace function getuid(eid_pro varchar2) return number is
l_value number;
begin
select uniqueid
into l_value
from enrollment
where eid = eid_pro;
return l_value;
end;
And then select the function.
select getuid('245698154') from dual;
In that case please use a function and then you can use it in a select statement which can show the result in the grid.
create or replace function getuid(eid_pro varchar2) return number is
l_value number;
begin
select uniqueid
into l_value
from enrollment
where eid=eid_pro;
return l_value;
end ;
select getuid('245698154') from dual;

PL/SQL Dynamic SQL

I need help. I have a problem in constructing my PL/SQL block.
In the cursor, I have a query constructed, and i want to insert a filter on cursor. Below is an example:
DECLARE
code NUMBER;
parameters_amb myOthertable%ROWTYPE;
CURSOR test is SELECT id from mytable
if parameters_amb.test2 is not null then
where mytable.name = 'NAMETABLE'
else
where mytable.name = 'NAMETABLE2';
Can anyone assist me in this construction?
You can use a parameterized cursor:
DECLARE
code NUMBER;
parameters_amb myOthertable%ROWTYPE;
param mytable.name%TYPE;
CURSOR test (p_name VARCHAR2) is
SELECT id
FROM mytable
WHERE mytable.name = p_name;
BEGIN
if parameters_amb.test2 is not null then
param := 'NAMETABLE'
else
param := 'NAMETABLE2';
end if;
OPEN test(param);
-- Add code to fetch and read from cursor
END;
You can try it like this:
DECLARE
code NUMBER;
parameters_amb myOthertable%ROWTYPE;
CURSOR test is SELECT id
from mytable
WHERE (parameters_amb.test2 is not null AND mytable.name = 'NAMETABLE' )
OR (parameters_amb.test2 is null AND mytable.name = 'NAMETABLE2' );
Or like this:
DECLARE
code NUMBER;
parameters_amb myOthertable%ROWTYPE;
CURSOR test is SELECT id
from mytable
WHERE mytable.name =
CASE WHEN parameters_amb.test2 is not null THEN 'NAMETABLE'
WHEN parameters_amb.test2 is null THEN 'NAMETABLE2' END
DECLARE
stmt varchar2(1000);
code NUMBER;
parameters_amb myOthertable%ROWTYPE;
BEGIN
stmt := 'SELECT id from mytable';
if parameters_amb.test2 is not null
then
stmt := stmt||' where mytable.name = ''NAMETABLE''';
else
stmt := stmt||' where mytable.name = ''NAMETABLE2''';
end if;
OPEN test FOR stmt;
...
...
END;
Here is a simple solution:
DECLARE
code NUMBER;
parameters_amb myOthertable%ROWTYPE;
CURSOR test is SELECT id from mytable
where mytable.name = NVL2(parameters_amb.test2, 'NAMETABLE', 'NAMETABLE2');

Resources