I have a (simplified) Oracle SQL like this:
declare
xd number;
xm number;
DataOut sys_refcursor;
begin
xd := to_number(to_char(sysdate, 'dd'));
xm := to_number(to_char(sysdate, 'mm'));
open DataOut for
select * from dual;
end;
And I want to be able to fill a DataTable in .Net from the data returned in the DataOut parameter.
I have been trying various things but can't seem to access the DataOut cursor.
How would I call this?
OracleCommand c = new OracleCommand();
c.CommandType = CommandType.Text;
c.CommandText = SQL;
OracleParameter param = new OracleParameter();
param.Direction = ParameterDirection.Output;
param.OracleType = OracleType.Cursor;
param.ParameterName = "DataOut";
c.Parameters.Add(param);
c.Connection = (OracleConnection) this.GetConnection();
OracleString rowNum = "";
c.ExecuteOracleNonQuery(out rowNum);
// or c.ExecuteReader()
// or use OracleDataAdapter
DataTable returnTable = /* magic goes here */
I can edit the SQL but I'm not able to create functions or procedures.
Is this possible?
An anonymous PL/SQL block does not return anything so you won't be able to use the cursor you open in the anonymous PL/SQL block in your client application. In order to return the data to the client application, you would need to use a named PL/SQL block (i.e. a stored procedure or a stored function). If you are not allowed to create named PL/SQL blocks, you won't be able to return a cursor you open in PL/SQL to your client application.
select cursor(select * from dual) from dual;
Related
I am executing a SQL Server stored procedure in C#, but both my output parameters are returned blank. But when I run this stored procedure directly in SSMS, then I get values for both parameters. I used same input order no.
Can anyone tell me what's wrong in my code? Thank you
using (SqlConnection con = new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("wt_find_open_pick_ticket_count", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#input_order_no", order_no);
cmd.Parameters.Add("#status", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Parameters.Add("#results", SqlDbType.VarChar, 1000).Direction = ParameterDirection.Output;
con.Open();
cmd.ExecuteNonQuery();
MessageBox.Show(cmd.Parameters["#status"].Value.ToString());
MessageBox.Show(cmd.Parameters["#results"].Value.ToString());
}
ALTER procedure wt_find_open_pick_ticket_count
#input_order_no varchar(20),
#results varchar(1000) OUTPUT,
#status int OUTPUT
AS
SELECT
status =
CASE
WHEN COUNT(oe_pick_ticket.pick_ticket_no)>0 THEN 0
ELSE 1
END,
results =
CASE
WHEN COUNT(oe_pick_ticket.pick_ticket_no)> 0 THEN 'Message'
ELSE ''
END
FROM oe_pick_ticket with (nolock)
WHERE
oe_pick_ticket.order_no = #input_order_no
AND oe_pick_ticket.invoice_no IS NULL
AND oe_pick_ticket.delete_flag = 'N'
AND oe_pick_ticket.print_date > '2014-01-01'
GROUP BY oe_pick_ticket.order_no
This stored procedure returns a resultset. It does not return output parameters. In order to return output paramters, SP has to change to something like:
select
#paramout1 = val1,
#paramout2 = val2
Notice "#" that is preceding parameter names.
I have a Postgres database with a stored procedure that returns JSON documents, based on the article here: http://www.sqlines.com/postgresql/npgsql_cs_result_sets
The procedure is represented like this:
-- Procedure that returns a single result set (cursor)
CREATE OR REPLACE FUNCTION get_data_test() RETURNS refcursor AS $$
DECLARE
ref refcursor; -- Declare a cursor variable
BEGIN
OPEN ref FOR -- Open a cursor
SELECT row_to_json(r) AS data
FROM
(
SELECT *
FROM data AS d
) r;
RETURN ref; -- Return the cursor to the caller
END;
$$ LANGUAGE plpgsql;
I am then running the following code from a .net console app:
// Making connection with Npgsql provider
using (NpgsqlConnection conn = new NpgsqlConnection(connstring))
{
conn.Open();
var trans = conn.BeginTransaction();
var cmd = new NpgsqlCommand("get_data_test", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Transaction = trans;
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
Trace.WriteLine(reader[0]);
}
}
The output is a single instance wit the name of the refcursor, rather than the actual data:
< unnamed portal 1 >
If I run the select query directly in the command text, the result set is returned as expected. I've also tried explicitly calling the proc via text using "SELECT get_data_test()" but this also fails with just the cursor name.
I don't believe I am missing a step and this refcursor should be returned unbundled. What am I doing wrong?
As it happens, the tutorial was wrong:
Nice GitHub bug report: https://github.com/npgsql/npgsql/issues/1777
Correct answer:
-- Procedure that returns a single result set (cursor)
CREATE OR REPLACE FUNCTION get_data_test() RETURNS TABLE (data JSON) AS $$
BEGIN
RETURN query
SELECT row_to_json(r) AS data
FROM
(
SELECT *
FROM data AS d
) r;
END;
$$ LANGUAGE plpgsql;
What I need:
In PLS/SQL on an Oracle DB, create a stored procedure or function with parameters, which given a declared table of , where is a ROW of a table (with all the fields), returns the resultset following the conditions given in the parameters. After, I need to call them from Microsoft Entity Framework with edmx file.
Basically the need is to being able to provide a quick report of the table contents into a pdf, matching some filters, with an oracle db.
The mantainer must be able, provided a script I give, to create and add new reports, so this needs to be dynamic.
Here's what I've got so far:
CREATE OR REPLACE type THETABLEIWANTTYPE as table of THETABLEIWANT%TYPE
create function
SCHEMA.THETABLEIWANT_FUNCTION(PARAM_GR in number default 1)
return THETABLEIWANTTYPE
PIPELINED
as
result_table THETABLEIWANTTYPE
begin
SELECT S.id, S.idg, S.sta, S.tab
Bulk collect into result_table
from SCHEMA.THETABLEIWANT S
WHERE IDGR = PARAM_GR
IF result_table.count > 0 THEN
for i in result_table.FIRST .. result_table.LAST loop
pipe row (result_table(i))
end loop
end if
return
end;
But it's not working. It gives errors.
Running CREATE TYPE I get:
Compilation errors for TYPE SCHEMA.THETABLEIWANT
Error: PLS-00329: schema-level type has illegal reference to
SCHEMA.THETABLEIWANT
The mantainer will launch the script creating a TYPE of the row of the table I need, then the function should return a table with the records.
Then calling it from Entity Framework I should be able to execute it like I'm calling a normal select from my table, IE:
``_dbContext.THETABLEIWANT.Where(x => x.IDGR = Param_gr).ToList();
The problem is that mantainers should be able to generate new kind of reports with any select inside without the need of my intervention on the software code.
Any hint?
It's ok also to bulk all the select result into a temp table but it has to be dynamic as column will be changing
I ended up to write a PLS/SQL procedure that returns a cursor and managing it from C# code with Oracle.ManagedDataAccess Library.
Here's the procedure, for anyone interested:
CREATE OR REPLACE PROCEDURE SCHEMA.PROC_NAME(
PARAM_1 VARCHAR2,
RESULT OUT SYS_REFCURSOR)
IS
BEGIN
OPEN RESULT FOR
SELECT A, V, C AS MY_ALIAS from SCHEMA.TABLE WHERE FIELD = PARAM_1 AND FIELD_2 = 'X';
END;
And here's the C# code for calling and getting the result:
OracleConnection conn = new OracleConnection("CONNECTIONSTRING");
try
{
if (conn.State != ConnectionState.Open)
conn.Open();
List<OracleParameter> parametri = new List<OracleParameter>()
{
new OracleParameter
{
ParameterName = nameof(filter.PARAM_1),
Direction = ParameterDirection.Input,
OracleDbType = OracleDbType.NVarchar2,
Value = filter.PARAM_1
}
};
OracleCommand cmd = conn.CreateCommand();
cmd.Parameters.AddRange(parametri.ToArray());
OracleParameter cursor = cmd.Parameters.Add(
new OracleParameter
{
ParameterName = "RESULT",
Direction = ParameterDirection.Output,
OracleDbType = OracleDbType.RefCursor
}
);
cmd.CommandText = procedureName;
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
using (OracleDataReader reader = ((OracleRefCursor)cursor.Value).GetDataReader())
{
if (reader.HasRows)
while (reader.Read())
{
//Iterate the result set
}
}
}
catch(Exception ex)
{
//Manage exception
}
Can you help me to pass a value from C# to refCursor type. I tried to send dataTable as shown in below link, but its not working.
Pass datatable to refcursor of Oracle stored procedure
Stored procedure:
PROCEDURE PROC_INS( P_USERID IN VARCHAR2,
P_ATTACH_LIST IN SYS_REFCURSOR,
P_out OUT NUMBER,
P_msg OUT VARCHAR2) AS
V_BRS_USERID VARCHAR2(50);
V_ATTACHMENT_TYPE_ID BRS_USER_ATTACHMENT.ATTACHMENT_TYPE_ID%TYPE;
V_FILE_NAME BRS_USER_ATTACHMENT.FILE_NAME%TYPE;
V_FILE_SIZE BRS_USER_ATTACHMENT.FILE_SIZE%TYPE;
V_FILE_DESCR BRS_USER_ATTACHMENT.FILE_DESCR%TYPE;
BEGIN
LOOP
FETCH P_ATTACH_LIST INTO V_BRS_USERID, V_ATTACHMENT_TYPE_ID,V_FILE_NAME, V_FILE_SIZE, V_FILE_DESCR;
EXIT WHEN P_ATTACH_LIST%NOTFOUND;
INSERT INTO USER_ATTACHMENT VALUES
(SEQ_RER_EMP_REP_ID.NEXTVAL,
V_BRS_USERID,
V_ATTACHMENT_TYPE_ID,
V_FILE_NAME,
V_FILE_SIZE,
V_FILE_DESCR,
NULL,
NULL,
0,
0,
'A',
P_USERID,
SYSDATE,
NULL,
NULL
);
END LOOP;
CLOSE P_ATTACH_LIST;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK; -- Transaction mgmt
p_out := 2;
p_msg := sqlerrm;
END PROC_REG_INS_ATTACH;
This is a duplicate post by this user. See Pass datatable to refcursor of Oracle stored procedure
You can't bind a DataTable to a Ref Cursor. You'll need to pass in another ref cursor and you can only get that as the output of a stored procedure/function, or a query against a table in an anonymous block... perhaps you can create a wrapper stored procedure that uses different data types, such as associative arrays.
http://www.oracle.com/technetwork/issue-archive/2006/06-jan/o16odpnet-087852.html
Use OracleCommand i OracleParameter classes. Notice ParameterDirection property of OracleParameter.
Here is the example from my code, I am calling web_shop_interface.kreiraj_mp_racun stored procedure, and setting params for it:
var fnRac = new OracleCommand();
fnRac.Connection = conn;
fnRac.CommandText = "web_shop_interface.kreiraj_mp_racun";
fnRac.CommandType = CommandType.StoredProcedure;
var ret = new OracleParameter("ret", OracleDbType.Varchar2);
ret.Direction = ParameterDirection.ReturnValue;
ret.Size = 4096;
fnRac.Parameters.Add(ret);
var p1 = new OracleParameter("did", OracleDbType.Decimal);
p1.Value = 15m;
p1.Direction = ParameterDirection.Input;
fnRac.Parameters.Add(p1);
var p2 = new OracleParameter("prn", OracleDbType.Varchar2);
p2.Value = "Invoice 15";
p2.Direction = ParameterDirection.Input;
fnRac.Parameters.Add(p2);
fnRac.ExecuteNonQuery();
I have a stored procedure in Oracle which receives an input parameter of type varchar2 varying array. The procedure works and if you invoke it from SQL, what I need is called from C#.
My script is this:
CREATE OR REPLACE PROCEDURE INTEGRATOR.PRC_TEST_PARAM_ARRAY (p_nros_moviles integrator.NROMOVIL_ARRAY) IS
BEGIN
FOR i IN 1..p_nros_moviles.count LOOP
IF p_nros_moviles(i) IS NOT NULL THEN
INSERT INTO INTEGRATOR.TEST_PARAM_ARRAY VALUES (p_nros_moviles(i));
END IF;
END LOOP;
END;
/
My user type:
CREATE OR REPLACE TYPE INTEGRATOR.NROMOVIL_ARRAY AS
VARYING ARRAY(100) OF VARCHAR2(15);
/
My invoke from PLSQL
DECLARE
v_array integrator.NROMOVIL_ARRAY;
BEGIN
v_array := integrator.NROMOVIL_ARRAY('9999999', '66666666');
integrator.prc_test_param_array(v_array);
END;
And I try this way from c#
try
{
using (OracleConnection connection = new OracleConnection())
{
connection.ConnectionString = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)" +
"(HOST=10.10.10.10)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)" +
"(SID=PORTANODE)));User Id=user;Password=*****;";
using (OracleCommand cmd = new OracleCommand("INTEGRATOR.PRC_TEST_PARAM_ARRAY", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
OracleParameter p = new OracleParameter();
p.ParameterName = "P_NROS_MOVILES";
p.OracleDbType = OracleDbType.Array;
p.Direction = ParameterDirection.Input;
p.UdtTypeName = "INTEGRATOR.NROMOVIL_ARRAY";
//p.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
p.Value = new string[] { "XXXX", "YYYY" };
cmd.Parameters.Add(p);
connection.Open();
cmd.ExecuteNonQuery();
MessageBox.Show("Ejecutado");
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Someone could guide me I need to change to make it work
Be patient, Wait and wait.. it takes hell of a long time .. that is my experience
I'm not sure but I think that System.Data.OracleClient doesn't really support user defined arrays.
I'd try to write a helping stored function, which takes for example a comma separated string (these will be the values of your varray type), and splits it to values using WHILE LOOP and SUBSTR. Then in each iteration it adds the actual VARCHAR2 to a temporary integrator.NROMOVIL_ARRAY type variable using the EXTEND(1) to make place for the new value.
In the end the function returns the temporary integrator.NROMOVIL_ARRAY, and this value could be used in the stored procedure.