Split variable and then execute query in Oracle - oracle

I have a IN parameter for P_R4GSTATE where I am getting values for the procedure as "Rajasthan,Maharashtra,Haryana"
And the procedure is below:
PROCEDURE GET_VENDOR_INFO
(
PVENDOR_NAME IN NVARCHAR2,
P_R4GSTATE IN NVARCHAR2,
P_OUTVENDOR OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN P_OUTVENDOR FOR
SELECT * FROM IPCOLO_IPFEE_CALC_MST WHERE CIRCLE=P_R4GSTATE;
END IF;
END GET_VENDOR_INFO;
The issue is that data might be their in any one of those State in the table, how to execute and check for that.

Split it to rows and use in IN clause:
open p_outvendor for
select *
from ipcolo_ipfee_calc_mst
where circle in (select regexp_substr(p_r4gstate, '[^,]+', 1, level)
from dual
connect by level <= regexp_count(p_r4gstate, ',') + 1
);

Related

How to convert this Oracle stored procedure into a SQL Server stored procedure?

I have a stored procedure from Oracle mentioned below which gets a comma seperated string parameter as input, splits it via a loop and returns the path of the id got from splitting the csv. How do I create a procedure which works same like this in SQL Server?
create or replace PROCEDURE FILE_LOOP(V_FID IN varchar2,
V_NAME OUT VARCHAR2) IS
BEGIN
FOR ITEM IN (SELECT V.PATHH||'\'|| V.NAME AS PATH
FROM FILES T INNER JOIN
Table2 V ON T.FOLID=V.ID
WHERE T.ID IN (SELECT TRIM(REGEXP_SUBSTR(V_FID,'[^,]+', 1, LEVEL))
FROM DUAL
CONNECT BY LEVEL <= 1+ REGEXP_COUNT(V_FID , ',')))
LOOP
v_name:=v_name||item.PATH;
END LOOP;
END;
Please help me write a procedure which gives exact same output in sql server? I'm new to sql server.
I think this is what you want :
if object_id('FILE_LOOP', 'P') is not null
drop procedure FILE_LOOP;
go
create PROCEDURE
FILE_LOOP(
#V_FID varchar(4000),
#V_NAME VARCHAR(4000) OUT) AS
BEGIN
SET NOCOUNT ON;
DECLARE ITEM CURSOR FOR
SELECT
ISNULL(V.PATHH, '') + '' +
ISNULL(V.NAME, '') AS PATH
FROM
FILES T
INNER JOIN Table2 V ON T.FOLID=V.ID
WHERE T.ID IN( SELECT
RTRIM(LTRIM(REGEXP_SUBSTR(#V_FID ,'[^,]+', 1, LEVEL));
FROM DUAL
CONNECT BY LEVEL <= 1 + REGEXP_COUNT(#V_FID ,',')))
WHILE 1=1
BEGIN
set #v_name=isnull(#V_NAME, '') + ISNULL(item.PATH, '');
END;
FETCH ITEM INTO;
END;
CLOSE ITEM;
DEALLOCATE ITEM;

Oracle PL/SQL - Receive a list of values as IN parameter, use them in the WHERE clause and return the results in a procedure

I need to create an Oracle procedure that receives a list of values, let's say Customer IDs, and uses those IDs in the WHERE clause of a SELECT statetement searching for all those Customer IDs in a table. The resulting columns and rows of this table must be returned by the procedure to the caller.
The quantity of Customer IDs is variable.
I imagine I should use cursors for this and the procedure would be declared similarly to this:
CREATE PROCEDURE (c_customers IN SYS_REFCURSOR, c_results OUT sys_refcursor) IS BEGIN ... but I don’t know how to manipulate those cursors.
I think you need to take customer ids as string input.
see if the following can help:
CREATE PROCEDURE YOUR_PROC_NAME (
C_CUSTOMERS IN VARCHAR2,
C_RESULTS OUT SYS_REFCURSOR
) IS
BEGIN
OPEN C_RESULTS FOR
SELECT *
FROM YOUR_TABLE
WHERE YOUR_COLUMN IN (
SELECT REGEXP_SUBSTR(C_CUSTOMERS, '[^,]+', 1, LEVEL)
FROM DUAL
CONNECT BY REGEXP_SUBSTR('SMITH,ALLEN,WARD,JONES', '[^,]+', 1, LEVEL) IS NOT NULL
);
END;
Cheers!!
an alternative solution is to use the collections:
First you have to create a global collection as a type
CREATE OR REPLACE TYPE tab_number is TABLE OF NUMBER;
you can then use it as a type of your arguments in your procedure
CREATE PROCEDURE YOUR_PROC_NAME (
in_id_list IN tab_number ,
C_RESULTS OUT SYS_REFCURSOR
) IS
BEGIN
OPEN C_RESULTS FOR
SELECT *
FROM YOUR_TABLE
WHERE YOUR_COLUMN IN (
SELECT column_value from table(in_id_list)
);
END;

oracle convert string parameter of stored procedure to number array

I am writing a stored procedure that needs an WHERE IN clause with an array of numbers. How can I pass this array of numbers to the SP.
What I thought is sending a string like '123,234,345' and than parse it in the SP before using it. Is this a good way of doing it? If yes, how can I make the below code work?
CREATE OR REPLACE PROCEDURE sp_test2
(
ids in varchar2,
cursor_ OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN cursor_ FOR
SELECT *FROM my_table
WHERE my_table.ID IN (
SELECT regexp_substr(ids,'[^:]+', 1, level) AS list FROM dual
CONNECT BY regexp_substr(ids, '[^:]+', 1, level) IS NOT NULL);
END;
/
For example (instead of the conversion code) when use like this: IN(ids)
i get ORA-01722: invalid number error
I really don't want to complicate things
If that's ok with you to simply pass a string of numbers separated by commas as a parameter and split it afterwards, then you can do it like this:
SELECT *FROM my_table
WHERE my_table.ID IN (
SELECT regexp_substr(ids,'[^,]+', 1, level) AS list FROM dual
CONNECT BY regexp_substr(ids, '[^,]+', 1, level) IS NOT NULL);
However, I don't think that using a collection complicates things too much.
Like I suggested, here is how to achieve it using dynamic SQL.
create or replace procedure sp_test2(IDS in varchar2, CURSOR_ out SYS_REFCURSOR)
is
L_SQL varchar2(400);
begin
L_SQL := 'select * from MY_TABLE where ID in (' || IDS || ')';
open CURSOR_ for L_SQL;
end;

ORACLE - Return cursor from stored procedure

I need to return a cursor object from a stored procedure, but I need to process data first.
For example, let's consider this simple stored procedure:
create or replace PROCEDURE TEST
(
query_str IN VARCHAR2,
CURSOR_ OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN CURSOR_ FOR query_str;
END;
This procedure returns data as is, with no postprocessing.
The improvement I need is the following:
process data coming from the execution of query_str;
return the processed data in the form of a cursor.
Anyone could suggest me a way to accomplish this?
Thanks
It is difficult to do what you are suggesting with dynamic SQL (unless all the statements you are passing to the procedure all have a similar output format). If you can know what the SELECT will be then you can store it in a collection and process it:
CREATE TABLE TEST_DATA ( id, name, dt ) AS
SELECT 1, 'A', SYSDATE FROM DUAL UNION ALL
SELECT 2, 'B', DATE '2017-01-01' FROM DUAL;
CREATE TYPE processed_data_obj AS OBJECT(
id INTEGER,
etag VARCHAR2(20)
);
/
CREATE OR REPLACE TYPE processed_data_table AS TABLE OF processed_data_obj;
/
CREATE OR REPLACE PROCEDURE TEST
(
CURSOR_ OUT SYS_REFCURSOR
)
AS
processed PROCESSED_DATA_TABLE;
BEGIN
-- Process it in the select statement
SELECT processed_data_obj(
id,
name || '_' || ROUND( ( dt - DATE '1970-01-01' ) * 24*60*60 )
)
BULK COLLECT INTO processed
FROM test_data;
-- Process it more in PL/SQL
FOR i IN 1 .. processed.COUNT LOOP
processed[i].etag := processed[i].etag || '_' || i;
END LOOP;
OPEN cursor_out FOR
SELECT *
FROM TABLE( processed );
END;
/

Are cursors necessary for queries in a procedure?

I'm rather new to Oracle and I was asked to write a procedure to query some data from a table. I built it with 2 arguments, a cursor and a number. Essentially I have:
PROCEDURE PROC_NAME (
cursor_name IN OUT NOCOPY MY_DEFINED_CURSOR_TYPE,
a_number IN NUMBER);
AS
BEGIN
OPEN CURSOR_NAME FOR
SELECT
column
FROM
table
WHERE
table.dat_value > (SYSDATE - a_number);
END PROC_NAME;
It works like a charm, and I'm able to fetch the column from the cursor. My problem is that the requester doesn't want to pass in a cursor, they just want to pass in the number. I've never created a procedure that doesn't use a cursor to return the values of a query and the examples I have seen only ever do it that way. Is this possible?
You can use a collection:
CREATE PROCEDURE PROC_NAME (
a_number IN NUMBER,
numbers OUT SYS.ODCINUMBERLIST
)
AS
BEGIN
SELECT number_value
BULK COLLECT INTO numbers
FROM table_name
WHERE date_value > (SYSDATE - a_number);
END PROC_NAME;
Also, if you don't want to pass in a cursor then you can just pass one out:
CREATE OR REPLACE PROCEDURE PROC_NAME (
a_number IN NUMBER,
numbers OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN numbers FOR
SELECT number_value
FROM table_name
WHERE date_value > (SYSDATE - a_number);
END PROC_NAME;
Use a function instead ? But it's just a "stylistic" difference compared to procedure out parameter. Anyway the returned value have to be implicitly passed (unlike in SQL Server as noted by #ShannonSeverance).
function f(
p_days in number
) return my_defined_cursor_type is
v_cur my_defined_cursor_type;
begin
open v_cur for
select
column
from
table
where
table.dat_value > (sysdate - p_days);
return v_cur;
end;
/
Usage
declare
v_cur my_defined_cursor_type := f(42);
begin
-- use v_cur as you like
end;
If you want to apply some PL/SQL logic, but remain using select for querying the data (i.e not pass in a cursor - use pipelined functions.
You need to define the TYPEs of the result row and table; FETCH the cursor and PIPE the results in the function.
CREATE or replace type MY_DEFINED_ROW_TYPE as object
(
txt VARCHAR2(30)
);
/
create or replace type MY_DEFINED_TABLE_TYPE as table of MY_DEFINED_ROW_TYPE
/
create or replace function FUN_NAME( a_number IN NUMBER) return
MY_DEFINED_TABLE_TYPE
PIPELINED
as
cur MY_DEFINED_CURSOR_TYPE;
v_txt varchar2(30);
begin
OPEN cur
FOR
SELECT
column
FROM table
WHERE table.dat_value > (SYSDATE - a_number);
LOOP
FETCH cur INTO v_txt;
EXIT WHEN cur%NOTFOUND;
pipe row(v_txt);
END LOOP;
return;
end;
/
The usage:
select * from table (FUN_NAME(2));

Resources