I have a simple package defined as follows:
CREATE OR REPLACE PACKAGE wvParty IS
TYPE refParties IS REF CURSOR;
END wvParty;
CREATE OR REPLACE PACKAGE BODY wvParty IS
PROCEDURE proc_GetParties(
p_party_name IN OUT VARCHAR2,
x_party_info OUT refParties
)
IS
BEGIN
p_party_name := '%'||p_party_name||'%';
OPEN x_party_info FOR
SELECT party_id, party_number, party_type, party_name,
person_first_name, person_middle_name, person_last_name,
known_as, known_as2, known_as3, known_as4, known_as5
FROM hz_parties
WHERE 1=1
AND party_name LIKE p_party_name;
END;
END wvParty;
It gets created in the oracle db with no errors. In my code, I'm trying to call it using:
try
{
OracleConnection conn = new OracleConnection(_connStr);
conn.Open();
OracleCommand cmd = conn.CreateCommand();
cmd.CommandText = "wvParty.proc_GetParties";
cmd.CommandType = CommandType.StoredProcedure;
OracleParameter partyName = new OracleParameter();
partyName.ParameterName = "p_party_name";
partyName.OracleDbType = OracleDbType.Varchar2;
partyName.Direction = ParameterDirection.InputOutput;
partyName.Value = "Bubba";
cmd.Parameters.Add(partyName);
OracleParameter refParties = new OracleParameter();
refParties.ParameterName = "x_party_info";
refParties.OracleDbType = OracleDbType.RefCursor;
refParties.Direction = ParameterDirection.Output;
cmd.Parameters.Add(refParties);
OracleDataReader rdr = cmd.ExecuteReader();
Yet, when I do I get the error:
PLS-00302: component 'PROC_GETPARTIES' must be declared.
So I'm at a loss. I've created the proc as part of the package, I've declared it as I believe I should but I'm having little success resolving this. Any suggestion?
I can't comment on the C# side of things, but there are a some problems on the Oracle side, like:
proc_GetParties is defined in the package body, but is not declared in the package specification. This means that it's not visible outside the package body. This explains why you are getting the PLS-00302 error.
The 1=1 condition is not needed in the WHERE clause.
Do you really want to change the value of p_party_name within the procedure and have that change to be visible to the caller? If not, it might be better to leave p_party_name unchanged and change the LIKE condition to party_name LIKE '%' || p_party_name || '%'.
Related
From C# Code, I'm trying to call a PACKAGE.PROCEDURE() from Oracle. In this simple example I should get one value from the procedure call, but all I get is error:
wrong number or types of arguments in call to 'RETURN_NUM'
The procedure is declared as follows:
PROCEDURE return_num(xNum OUT NUMBER) AS
BEGIN
xNum:= 50;
dbms_output.put_line('hello world ' || xNum);
END;
C# code:
Oraclecon.Open();
OleDbCommand myCMD = new OleDbCommand("TEST.return_num", Oraclecon);
myCMD.CommandType = CommandType.StoredProcedure;
myCMD.Parameters.Add("xNum", OleDbType.Numeric);
OleDbDataReader myReader;
myReader = myCMD.ExecuteReader();
Can some one please point out what I'm doing wrong. Then in a real scenario I would like to call a procedure that returns a set of values from a custom Type, such as:
TYPE r_interface_data IS RECORD
(
object_id VARCHAR2(16),
obj_type VARCHAR2(32)
);
TYPE t_interfase_data IS TABLE OF r_interface_data;
How can I approach that. Thanks!
UPDATE: In my particular case I ended-up doing the following approach
using (OleDbCommand cmd = new OleDbCommand("PACKAGE.procedure_name"))
{
cmd.CommandType = CommandType.StoredProcedure;
SqlManager sqlManager = new SqlManager();
return sqlManager.GetDataSet(cmd);
}
I don't think you're that far off... try this:
OracleCommand cmd = new OracleCommand("return_num", Oraclecon);
cmd.Parameters.Add(new OracleParameter("xNum", OracleDbType.Decimal,
ParameterDirection.Output));
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
OracleDecimal d = (OracleDecimal)cmd.Parameters[0].Value;
double result = d.ToDouble();
result now contains the out parameter from the procedure.
I think your problem is you were attempting to use a DbDataReader on a stored procedure. DbDataReader is for queries.
Also, I used ODP.net -- that may or may not have contributed to your issue, that you were using Ole.
I am using a code to call a Stored Procedure having 2 output and 1 input parameter. But i keep getting an error every time I call this stored proc:
CREATE PROCEDURE [dbo].[usp_StoredProcName]
#inputVal nvarchar(255),
#isError bit OUTPUT,
#errorInfo nvarchar(255) OUTPUT
AS BEGIN
DECLARE #totalRow int = 0;
DECLARE #inputValID uniqueidentifier;
SET #isError = 1;
SET #errorInfo = '';
SELECT #inputValID = [inputValID]
FROM testTable
WHERE inputVal = #inputVal;
IF #inputValID IS NULL
BEGIN
SET #isError = 0;
SET #errorInfo = 'inputVal not found';
RETURN
END
END
I have used couple of C# methods to call the stored proc and I get they all return this error:
Procedure or function 'usp_StoredProcName' expects parameter '#inputVal', which was not supplied.
C# Method 1 (to call the stored proc)
using (SqlConnection con = new SqlConnection(myFullConncectionStringToDB))
{
using (SqlCommand cmd = new SqlCommand("usp_StoredProcName", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#inputVal", "MyParamVal_12345");
cmd.Parameters["#isError"].Direction = ParameterDirection.Output;
cmd.Parameters["#errorInfo"].Direction = ParameterDirection.Output;
con.Open();
cmd.ExecuteNonQuery();
var isError = cmd.Parameters["#isError"].Value;
var errInfo = cmd.Parameters["#errorInfo"].Value;
con.Close();
}
}
Method 2 ( to call the stored proc)
SqlConnection con = new SqlConnection(myFullConncectionStringToDB);
SqlCommand cmd = new SqlCommand("usp_StoredProcName", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter in_parm = new SqlParameter("#inputVal", SqlDbType.NVarChar);
in_parm.Size = 255;
in_parm.Value = "MyParamVal_12345";
in_parm.Direction = ParameterDirection.Input;
cmd.Parameters.Add(in_parm);
SqlParameter out_parm = new SqlParameter("#errorInfo", SqlDbType.NVarChar);
out_parm.Size = 255;
out_parm.Direction = ParameterDirection.Output;
cmd.Parameters.Add(out_parm);
SqlParameter out_parm1 = new SqlParameter("#isError", SqlDbType.Bit);
out_parm1.Direction = ParameterDirection.Output;
cmd.Parameters.Add(out_parm1);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
Both of the above methods I tried return the same error:
Procedure or function 'usp_StoredProcName' expects parameter '#inputVal', which was not supplied.
Please tell me what am I doing wrong here in my C# code to execute the stored procedure.
I am clearly passing the parameter value in both of my methods but can't figure out why I keep getting this error.
Thank you for your help.
I usually break down the solution into pieces an make sure each one works.
First, test the Stored Procedure to make sure it works as planned. Sample call is below.
-- Switch to your database
USE [YourDatabase]
GO
-- Declare output variables
DECLARE #out_is_error bit;
DECLARE #out_error_info nvarchar(255);
-- Execute sp
EXECUTE [dbo].[usp_StoredProcName]
N'In Data',
#isError = #out_is_error OUTPUT,
#errorInfo = #out_error_info OUTPUT;
-- Show any SQL errors / return data
PRINT ##ERROR;
PRINT 'Error = ' + #out_error_info;
PRINT 'Flag = ';
PRINT CAST(#out_is_error as CHAR(1));
GO
Next, look at the C# piece of the puzzle. Aaron suggestion about correct database is a good one. Do you have two copies of the SP floating around?
Good luck.
I know there are a couple of other questions on here with the exact same issue, but I am 100% positive I don't have any type of permissions issue. The procedure executes fine from the query editor, but for some reason I can't get this proc to execute from a very simple ASP.net page. I should note this is my first attempt at creating an Oracle Proc.
Here is my code that calls the proc (just trying to call it and force results into the label)
string oradb = "connection string here";
OracleConnection conn = new OracleConnection(oradb);
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = "x.GETCURSORS";
cmd.CommandType = CommandType.StoredProcedure;
OracleParameter ACTNUM = new OracleParameter();
ACTNUM.OracleDbType = OracleDbType.Decimal;
ACTNUM.Direction = ParameterDirection.Input;
ACTNUM.Value ="12345";
cmd.Parameters.Add(ACTNUM);
OracleParameter REJECTS_C = new OracleParameter();
REJECTS_C.OracleDbType = OracleDbType.RefCursor;
REJECTS_C.Direction = ParameterDirection.Output;
cmd.Parameters.Add(REJECTS_C);
try
{
conn.Open();
OracleDataReader objReader = cmd.ExecuteReader();
Label3.Text = objReader.ToString();
}
catch (Exception ex)
{
Label3.Text = string.Format("Exception: {0}", ex.ToString());
}
Package specification:
PACKAGE "x"."REJECTS_DATA" IS
PROCEDURE "GETCURSORS" (
"ACTNUM" IN NUMBER,
"REJECTS_C" OUT SYS_REFCURSOR);
END "REJECTS_DATA";
Package body:
PACKAGE BODY "x"."REJECTS_DATA" IS
PROCEDURE "GETCURSORS" (
"ACTNUM" IN NUMBER,
"REJECTS_C" OUT SYS_REFCURSOR) IS
BEGIN
OPEN REJECTS_C FOR SELECT * FROM x.a
WHERE x.a.ACCOUNT = ACTNUM;
END "GETCURSORS";
END "REJECTS_DATA";
Assuming that the schema name is X, the package name is REJECTS_DATA, and the procedure name is GETCURSORS, at a minimum, the command would need to be
cmd.CommandText = "x.REJECTS_DATA.GETCURSORS";
If you are actually using case-sensitive identifers in PL/SQL (which I would strongly suggest avoiding), you would need to use case-sensitive identifiers in the procedure name as well.
We faced the same issue in our code and had to keep SCHEMA_NAME out of our proc call in C#, i.e. PACKAGE_NAME.PROC_NAME. We resolved this by creating a Synonym in the database with the SCHEMA_NAME
looking for some help in identifying the correct method of calling an Oracle Procedure call from the given info below. I am using .NET 4 with Oracle.DataAccess.Client.
Below are the details of the Procedure from Oracle:
CREATE OR REPLACE PACKAGE APPS.syk_serial_num_details
AS
TYPE account_rec_type IS RECORD(
inv_item_id NUMBER
,item_num VARCHAR2(40)
,item_desc VARCHAR2(240)
,acc_num VARCHAR2(30)
,ship_to VARCHAR2(1000)
,bill_to VARCHAR2(1000)
);
TYPE account_set IS TABLE OF account_rec_type;
PROCEDURE get_prod_details(
p_serial_num IN VARCHAR2
,p_acc_nums IN VARCHAR2
,p_ship_tos IN VARCHAR2
,p_acc_set OUT syk_serial_num_details.account_set
,p_status OUT VARCHAR2
);
END syk_serial_num_details
here are some more details showing the param types and size...below is an example of the procedure call from Toad interface:
DECLARE
l_serial_num csi_item_instances.serial_number%type;
l_acc_nums VARCHAR2(100);
l_ship_tos VARCHAR2(100);
l_acc_set syk_serial_num_details.account_set;
l_status VARCHAR2(80);
BEGIN
l_serial_num := '1025200453';
l_acc_nums := '8165';
l_ship_tos := '10332';
l_acc_set := syk_serial_num_details.account_set();
syk_serial_num_details.get_prod_details(p_serial_num => l_serial_num
,p_acc_nums => l_acc_nums
,p_ship_tos => l_ship_tos
,p_acc_set => l_acc_set
,p_status => l_status
);
Dbms_output.put_line('Status ::' || l_status);
IF(l_acc_set.count >0) then
FOR i IN 1 .. l_acc_set.count
LOOP
l_acc_set.extend;
DBMS_OUTPUT.put_line( 'Item_Number:'
|| l_acc_set(i).item_num||'|'
|| ' Desc:'
|| l_acc_set(i).item_desc||'|'
|| ' Accunt Number:'
|| l_acc_set(i).acc_num||'|'
|| ' Ship To:'
|| l_acc_set(i).ship_to||'|'
|| ' Bill To:'
|| l_acc_set(i).bill_to||'|'
);
END LOOP;
end if;
END;
So...I am having LOTS of trouble trying to identify the proper type for the p_acc_set output.
Below is my current C# code:
OracleConnection conn = getOracleConnection();
List<AccountSearchResultsDto> ProductInfoList = new List<AccountSearchResultsDto>();
using (conn)
{
conn.Open();
using (OracleCommand cmd = new OracleCommand("syk_serial_num_details.get_prod_details", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
//ASSIGN PARAMETERS TO BE PASSED
OracleParameter param1 = new OracleParameter("p_serial_num", OracleDbType.Varchar2);
param1.Direction = ParameterDirection.Input;
param1.Size = 100;
param1.Value = "1025200453";
cmd.Parameters.Add(param1);
OracleParameter param2 = new OracleParameter("p_acc_nums", OracleDbType.Varchar2);
param2.Direction = ParameterDirection.Input;
param2.Size = 100;
param2.Value = "8165";
cmd.Parameters.Add(param2);
OracleParameter param3 = new OracleParameter("p_ship_tos", OracleDbType.Varchar2);
param3.Direction = ParameterDirection.Input;
param3.Size = 100;
param3.Value = "10332";
cmd.Parameters.Add(param3);
//PARAMETERS USED TO RETURN RESULT OF PROCEDURE CALL
OracleParameter param4 = new OracleParameter("p_acc_set", OracleDbType.Object);
param4.Direction = ParameterDirection.Output;
param4.Size = 1;
cmd.Parameters.Add(param4);
OracleParameter param5 = new OracleParameter("p_status", OracleDbType.Varchar2);
param5.Direction = ParameterDirection.Output;
param5.Size = 300;
cmd.Parameters.Add(param5);
cmd.ExecuteNonQuery();
if (cmd.Parameters["p_status"].Value.ToString().Equals("SUCCESS"))
{
//Get results from p_acct_set and put values in list
}
}
}
As of now - attempting the above I am getting the following error:
Invalid parameter binding
Parameter name: p_acc_set
Should i be using the OracleParameter UdtTypeName reference for the p_acc_set?
I am very new to Oracle Procedure calls so please forgive my inexperience.
Any help is appreciated! thanks in advance!!
-R
The difference i spotted for parameter "p_acc_set" and "p_status" compare to others is that they did not assign Size on them please try to assign size on them and should fix your issue
I did not find the MSDN explaining very clearly on OracleParamter.Size property. But i did notice a line in the remarks that says
The line is taken from MSDN remarks :
For bidirectional and output parameters, and return values, you must
set the value of Size.
There's the property BindByName of OracleCommand class (defaulted to false) to handle this.
You should set it to true before executing the command to avoid that error!
for further informations read this too!!
Edit
Sorry, I didn't notice there was a PL/SQL Nested Table!! I don't think that Oracle supports a bind for that (especially if it contains records instead of simple values).
Associative Arrays, PL/SQL Nested tables and PL/SQL Vararrays are very similar data types so probably here they intend all the three things with the name Associative Arrays.
Using a Nested Table of User defined Types in place of it should solve your problem but it will become very trivial to handle for a newbie ...If so you should redefine the procedure to use the new data type and setting UdtTypeName parameter in the C# code is not the only thing to do.
Greetings all,
I have a question. I am trying to build a parametrized query to get me the number of rows from a table in Oracle. Rather simple. However I am an Oracle newbie..
I know in SQL Server you can do something like:
Select #outputVariable = count(*) from sometable where name = #SomeOtherVariable
and then you can set up an Output parameter in the System.Data.SqlClient to get the #outputVariable.
Thinking that one should be able to do this in Oracle as well, I have the following query
Select count(*) into :theCount from sometable where name = :SomeValue
I set up my oracle parameters (using System.Data.OracleClient - yes I know it will be deprecated in .Net 4 - but that's what I am working with for now) as follows
IDbCommand command = new OracleCommand();
command.CommandText = "Select count(*) into :theCount from sometable where name = :SomeValue";
command.CommandType = CommandType.Text;
OracleParameter parameterTheCount = new OracleParameter(":theCount", OracleType.Number);
parameterTheCount .Direction = ParameterDirection.Output;
command.Parameters.Add(parameterTheCount );
OracleParameter parameterSomeValue = new OracleParameter(":SomeValue", OracleType.VarChar, 40);
parameterSomeValue .Direction = ParameterDirection.Input;
parameterSomeValue .Value = "TheValueToLookFor";
command.Parameters.Add(parameterSomeValue );
command.Connection = myconnectionObject;
command.ExecuteNonQuery();
int theCount = (int)parameterTheCount.Value;
At which point I was hoping the count would be in the parameter parameterTheCount that I could readily access.
I keep getting the error ora-01036 which http://ora-01036.ora-code.com tells me to check my binding in the sql statement. Am I messing something up in the SQL statement? Am I missing something simple elsewhere?
I could just use command.ExecuteScaler() as I am only getting one item, and am probably going to end up using that, but at this point, curiosity has got the better of me. What if I had two parameters I wanted back from my query (ie: select max(ColA), min(ColB) into :max, :min.....)
Thanks..
Some versions of the ADO does not need the colon : configuring OracleParameter.
Instead of:
new OracleParameter(":theCount", OracleType.Number);
try
new OracleParameter("theCount", OracleType.Number);
Anyway, I think you have to use the ExecuteScalar() function of the IDbCommand and avoiding use of into (which I'm not sure it's valid on this context). I mean:
IDbCommand command = new OracleCommand();
command.CommandText = "Select count(*) from sometable where name = :SomeValue";
command.CommandType = CommandType.Text;
OracleParameter parameterSomeValue = new OracleParameter("SomeValue", OracleType.VarChar, 40);
parameterSomeValue .Direction = ParameterDirection.Input;
parameterSomeValue .Value = "TheValueToLookFor";
command.Parameters.Add(parameterSomeValue );
command.Connection = myconnectionObject;
int theCount = (int)command.ExecuteScalar();
Disclaimer: The code have not been compiled, and may be have any little error.
Update: If you take a look on the Oracle SELECT syntax, you will see that The SELECT INTO sentence is not recognized. But it's valid in PLSQL syntax as you can see here. You can try one of the following to see if it works (not tested):
command.CommandText = "begin Select count(*) into :someCount from sometable where name = :SomeValue; end;";
I think the problem is that you have a trailing space in the parameter name for parameterTheCount.
Edit
Now remove the colons from the parameter names in the constructor to OracleParameter.