I have an inventory system and this code is for when a user creates a new item. It's supposed to insert a 0 value in the inventory table since it's a new item. My code is:
string queryAdd4 = "INSERT INTO [inventory]([item_id],[item_qty],[item_date],[item_type]) VALUES(#myID,#myQty,#myDate,#myType)";
using (SqlCommand cmd = new SqlCommand(queryAdd4, Con))
{
cmd.Parameters.Add(new SqlParameter("#myID", item_id));
cmd.Parameters.Add(new SqlParameter("#myQty", 0));
cmd.Parameters.Add(new SqlParameter("#myDate", dateNow));
cmd.Parameters.Add(new SqlParameter("#myType", 1));
Con.Open();
cmd.ExecuteNonQuery();
Con.Close();
}
With that code, i'm getting an error saying:
The parameterized query '(#myID int,#myQty bigint,#myDate datetime,#myType int)
INSERT INT' expects the parameter '#myQty', which was not supplied
Out of curiosity, I tried replacing the 0 beside the #myQty with 1 and the query worked without problems. I also tried manually running the query through the Server Explorer and that worked as well. So I'm guessing 0 is not a valid number to insert when using parameterized queries? If so, how would I go about doing it?
When using two parameters with SqlParameter Constructor, there are two choices:
SqlParameter(string parameterName, SqlDbType dbType)
SqlParameter(string parameterName, object value)
When using an integer, the first choice is used. If you want to use the two parameter constructor, you have to cast 0 to an object:
cmd.Parameters.Add(new SqlParameter("#myQty", (object)0));
Also regard the oneliner from Sinatr in the comments:
cmd.Parameters.Add(new SqlParameter("#myQty", 0) { SqlDbType = SqlDbType.Int });
try to set the specific type to your parameter like here;
Take a look at a database and set it according to the type which is set to the column.
string queryAdd4 = "INSERT INTO [inventory]([item_id],[item_qty],[item_date],[item_type]) VALUES(#myID,#myQty,#myDate,#myType)";
using (SqlCommand cmd = new SqlCommand(queryAdd4, Con))
{
cmd.Parameters.Add(new SqlParameter("#myID", item_id));
var parameter = new SqlParameter()
parameter.ParameterName = "#myQty";
parameter.SqlDbType = SqlDbType.Int;
parameter.Direction = ParameterDirection.Input;
parameter.Value = 0;
cmd.Parameters.Add(parameter);
cmd.Parameters.Add(new SqlParameter("#myDate", dateNow));
cmd.Parameters.Add(new SqlParameter("#myType", 1));
Con.Open();
cmd.ExecuteNonQuery();
Con.Close();
Sources:
List of types:
https://msdn.microsoft.com/en-us/library/system.data.sqldbtype(v=vs.110).aspx
Configuring query parameters:
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/configuring-parameters-and-parameter-data-types
Hope it helps.
Related
How do I insert into parameters from different tables using OleDB?
I have 3 tables:
1. itemTbl
2. crateTbl
3. contentTbl
itemTbl has: itemID, itemName, itemDesc
crateTbl has: crateID, crateName
contentTbl has: crateID, itemID, qty
contentTbl is the contents of the crate and the qty of each
I need it to select values in different tables I use WHERE. I have tried a similar code using a local db and service based db and they allow me, but OleDB doesn't let me use VALUES((SELECT))....
Error message:
System.Data.OleDb.OleDbException: 'Query input must contain at least one table or query.
My code:
cmd.Dispose();
cmd.CommandText = #"INSERT INTO contentTbl(crateID,itemID,qty) VALUES((SELECT crateTbl.crateID FROM crateTbl WHERE crateTbl.crateID=?),(SELECT itemTbl.itemID FROM itemTbl WHERE itemTbl.itemID = ?), ?)";
cmd.Connection = con;
cmd.Parameters.Add(new OleDbParameter("crateID", txtCrate.Text));
cmd.Parameters.Add(new OleDbParameter("itemID", txtItem.Text));
cmd.Parameters.Add(new OleDbParameter("qty", txtQty.Text));
con.Open();
cmd.ExecuteNonQuery();
con.Close();
MessageBox.Show("Done!");
da.SelectCommand = new OleDbCommand("SELECT * FROM contentTbl", con);
da.Fill(dt);
dgvContent.DataSource = dt;
The error message is quite descriptive. Access doesn't support subqueries without a main query, so change the syntax round to use one of the subqueries as your main query:
INSERT INTO contentTbl(crateID,itemID,qty)
SELECT crateTbl.crateID,(SELECT itemTbl.itemID FROM itemTbl WHERE itemTbl.itemID = ?), ?
FROM crateTbl WHERE crateTbl.crateID=?
Note that parameters are passed by position, and rewriting this query does require you to re-order parameters:
cmd.Parameters.Add(new OleDbParameter("itemID", txtItem.Text));
cmd.Parameters.Add(new OleDbParameter("qty", txtQty.Text));
cmd.Parameters.Add(new OleDbParameter("crateID", txtCrate.Text));
If you don't like the main query/subquery syntax, you can go for a cross join too:
INSERT INTO contentTbl(crateID,itemID,qty)
SELECT crateTbl.crateID, itemTbl.itemID, ?
FROM crateTbl,itemTbl
WHERE crateTbl.crateID=? AND itemTbl.itemID = ?
(Parameter order needs to be adjusted again but you can figure that out).
I am not sure about the syntax. I always use it like (this is from VB, but C# should be similar) :
cmd.Parameters.Addwithvalue("crateID", txtCrate.Text)
I have tried this and it sort of works, but for some reason works only with values for the items table as ID's. If I have an ID (they're ints) that crateTbl has but itemTbl doesn't, it doesn't insert.
cmd.Dispose();
cmd.CommandText = #"INSERT INTO contentTbl(itemID,crateID,qty) SELECT itemTbl.itemID,(SELECT crateTbl.crateID FROM crateTbl WHERE crateTbl.crateID = ?), ? FROM itemTbl WHERE itemTbl.itemID=?";
cmd.Connection = con;
cmd.Parameters.Add(new OleDbParameter("itemID", txtItem.Text));
cmd.Parameters.Add(new OleDbParameter("qty", txtQty.Text));
cmd.Parameters.Add(new OleDbParameter("crateID", txtCrate.Text));
con.Open();
cmd.ExecuteNonQuery();
con.Close();
MessageBox.Show("Done!");
dt2.Clear();
I'm trying to call an Oracle Function from our C# application, but I either get the following errors. I think I have two problems:
I want to call this function, but some of the parameters can be null on the C# side so I don't know how to handle them.
I don't know if I need to add the return value to the parameters with ParameterDirection.ReturnValue on the OracleParameter object.
This is what I'm trying:
public int GetActivityRowCount(DateTime fromDate, DateTime thruDate, string grpCds, string catCds, string typCds, long? memNbr, long? subNbr, string searchBy, string dispActivity, string statCds, bool showUncategorized, string debugYN)
{
OracleCommand cmd = null;
try
{
StringBuilder sql = new StringBuilder();
sql.Append(" pack_SomePack.func_SearchRowCount");
cmd = new OracleCommand(sql.ToString(), this.Connection);
cmd.CommandType = CommandType.StoredProcedure;
// Don't know if I should add this guy
// cmd.Parameters.Add(new OracleParameter("RowCount", OracleDbType.Int16, ParameterDirection.ReturnValue));
cmd.Parameters.Add(new OracleParameter("FromDate", OracleDbType.Date, fromDate, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("ThruDate", OracleDbType.Date, thruDate, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("grpCds", OracleDbType.Varchar2, grpCds, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("catCds", OracleDbType.Varchar2, catCds, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("typCds", OracleDbType.Varchar2, typCds, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("memNbr", OracleDbType.Long, memNbr, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("SubNbr", OracleDbType.Long, SubNbr, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("searchBy", OracleDbType.Varchar2, searchBy, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("dispActivity", OracleDbType.Varchar2, dispActivity, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("statCds", OracleDbType.Varchar2, statCds, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("showUncategorized", OracleDbType.Char, showUncategorized? "Y" : "N", ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("debugYN", OracleDbType.Varchar2, debugYN, ParameterDirection.Input));
cmd.BindByName = true;
int activityRowCount = Convert.ToInt16(cmd.ExecuteScalar()); // Error here
return activityRowCount;
}
My function does the following:
FUNCTION func_SearchRowCount
(
in_FromDate IN DATE,
in_ThruDate IN DATE,
in_GrpCds IN VARCHAR2,
in_CatCds IN VARCHAR2,
in_TypCds IN VARCHAR2,
in_MemNbr IN Actv.PersNbr%TYPE,
in_SubNbr IN Actv.SubNbr%TYPE,
in_SearchBy IN VARCHAR2,
in_dispActivity IN VARCHAR2,
in_StatCds IN Ams.StatCd%TYPE,
in_UncategorizedYN IN CHAR,
in_DebugYN IN CHAR
) RETURN NUMBER AS
lvnCount NUMBER;
lvsSqlStr VARCHAR2(2000);
BEGIN
lvsSqlStr := 'SELECT COUNT(*) FROM SomeTable WHERE (Include a bunch of clauses..)';
BEGIN
EXECUTE IMMEDIATE lvsSqlStr
INTO lvnCount
USING (All the parameters);
END;
RETURN lvnCount;
END func_SearchRowCount;
I get the following error when running what's above.
PLS-00306: wrong number or types of arguments in call to 'FUNC_SEARCHROWCOUNT'
All the variables are bound with the correct amount, although I read somewhere that ODP.NET will remove the parameters with null as there .Value. Is this true? What should I pass in to indicate that there is no value for that parameter then?
You need 4 things at a minimum:
The first two: call ExecuteNonQuery and not ExecuteScalar as discussed in this MSDN thread and create the return value parameter. About a third of the way down on Accessing Oracle 9i Stored Procedures it shows this code and says
You execute the function in the same way as a stored procedure. Use a ParameterDirection.ReturnValue parameter to get the result returned by the function.
On the third, do use DbNull.Value because it is specifically designed as a placeholder to represent null values in a database, whereas null has meaning only for .NET. (Well, null is probably ok because the Oracle driver is probably smart enough to handle it; DbNull.Value is a good habit though because you're being explicit). You can do something like
new OracleParameter("typCds", OracleDbType.Varchar2, typCds ?? (object)DbNull.Value, ParameterDirection.Input));
And finally, you have bind by name on your parameters, but the names don't match the names of your parameters. Match the names exactly or bind by position.
As to the specific error, the return value is "an argument" and didn't bind he parameters correctly. Oracle wanted 13 parameters and you effectively gave it none.
there seems to be several problems with your code.
Oracle Type LONG is not same like in C#, LONG in Oracle DB allows you to store character data up to 2GB size. In C# it's an numeric type using 64 Bit. Since your submitted code does not explain what type of data your parameters in_MemNbr, in_SubNbr and in_StatCds in the package function are, i can only guess, what it is depending on your definitions of the parameter list in your c# method.
Your parameter names in C# in the "new OracleParameter("")" statements does not match the function parameters exactly. In Pl/Sql you added an "in_" prefix, but removed it in the c# code. With "cmd.BindByName = true;" you say to ODP.Net "Hey, bind the parameters in the collection by name rather than using position". In this case they must match exactly.
Your C# return value of the method is int (System.Int32), the return value of the PlSql package function is NUMBER. ODP.Net seems to return decimal in C# in case of numbers without specified scale. Maybe you run into a conversion/invalidcast exception when ODP.Net tries to convert the oracle number type into short (Int16) internally. Maybe you get an out of range exception when the returned count is greater than short.MaxValue. Try to specify Int32 as return value in your return value parameter creation.
OracleCommand implements IDisposable interface. Please ensure that your command is disposed, when not needed anymore, since the implementation of IDisposable interfaces in objects shows you that the object creates/uses some resources (managed or unmanaged) and must release them, when operations finished. Shortest way is to use the
"using" keyword of C#, which ensures a call of cmd.Dispose() when code execution leaves the block regardless if exception occured or block ends with success.
public int GetActivityRowCount(DateTime fromDate, DateTime thruDate, string grpCds, string catCds, string typCds, long? memNbr, long? subNbr, string searchBy, string dispActivity, string statCds, bool showUncategorized, string debugYN)
{
using (var cmd = new OracleCommand("pack_SomePack.func_SearchRowCount", this.Connection))
using (var result = new OracleParameter("result", OracleDbType.Int32, ParameterDirection.ReturnValue))
using (var fromDateParam = new OracleParameter("in_FromDate", OracleDbType.Date, fromDate, ParameterDirection.Input))
using (var thruDateParam = new OracleParameter("in_ThruDate", OracleDbType.Date, thruDate, ParameterDirection.Input))
using (var grpCdsParam = new OracleParameter("in_GrpCds", OracleDbType.Varchar2, grpCds, ParameterDirection.Input))
using (var catCdsParam = new OracleParameter("in_CatCds", OracleDbType.Varchar2, catCds, ParameterDirection.Input))
using (var typCdsParam = new OracleParameter("in_TypCds", OracleDbType.Varchar2, typCds, ParameterDirection.Input))
using (var memNbrParam = new OracleParameter("in_MemNbr", OracleDbType.Int64, memNbr, ParameterDirection.Input))
using (var subNbrParam = new OracleParameter("in_SubNbr", OracleDbType.Int64, SubNbr, ParameterDirection.Input))
using (var searchByParam = new OracleParameter("in_SearchBy", OracleDbType.Varchar2, searchBy, ParameterDirection.Input))
using (var dispActivityParam = new OracleParameter("in_dispActivity", OracleDbType.Varchar2, dispActivity, ParameterDirection.Input))
using (var statCdsParam = new OracleParameter("in_StatCds", OracleDbType.Varchar2, statCds, ParameterDirection.Input))
using (var uncategorizedYnParam = new OracleParameter("in_UncategorizedYN", OracleDbType.Char, showUncategorized ? "Y" : "N", ParameterDirection.Input))
using (var debugYnParam = new OracleParameter("in_DebugYN", OracleDbType.Char, debugYN, ParameterDirection.Input))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(result);
cmd.Parameters.Add(fromDateParam);
cmd.Parameters.Add(thruDateParam);
cmd.Parameters.Add(grpCdsParam);
cmd.Parameters.Add(catCdsParam);
cmd.Parameters.Add(typCdsParam);
cmd.Parameters.Add(memNbrParam);
cmd.Parameters.Add(subNbrParam);
cmd.Parameters.Add(searchByParam);
cmd.Parameters.Add(dispActivityParam);
cmd.Parameters.Add(statCdsParam);
cmd.Parameters.Add(uncategorizedYnParam);
cmd.Parameters.Add(debugYnParam);
cmd.BindByName = true;
cmd.ExecuteNonQuery();
return Convert.ToInt32(result.Value);
}
}
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 have a Datagridview of 46 columns consists of Date, Int and String Type. I want to insert the values to another oracle table.
private void loopGrid()
{
foreach (DataGridViewRow datarow in this.dataGridView1.Rows)
{
writeRecord(datarow);
}
}
private void writeRecord(DataGridViewRow datarow)
{
string sqlqry = "insert into Table (Date,Number) values(:Date,:Number)";
OracleCommand cmd = new OracleCommand(sqlqry, conn);
cmd.Parameters.Add(new OracleParameter(":Date", datarow["DATE"]))
cmd.Parameters.Add(new OracleParameter(":Number", datarow["Number"]));
cmd.CommandText = sqlqry;
cmd.ExecuteNonQuery();
}
I don't quite understand what I did wrong about passing the parameters. I'm pretty new to C#, what's the right way to pass the Datatype and value to the other oracle table?
Depending on the Oracle driver you are using, there may be an overload for the .Add method that accepts the value as the second parameter, or there may be an .AddWithValue method that does it explicitly. I think for ODP.net you have it right as just .Add.
Either way, these will derive the datatype from the datatype of the value.
Regarding your parameters, you need to omit the colon : character when invoking the parameters. I know in SQL Server, Sybase, SQLite and others you include them (a # in those cases), but in Oracle you leave them out during the parameter declaration. Interestingly, I think PostgreSQL accepts either methodology.
As such, I think this will work:
private void writeRecord(DataGridViewRow datarow)
{
string sqlqry = "insert into Table (Date,Number) values(:Date,:Number)";
OracleCommand cmd = new OracleCommand(sqlqry, conn);
cmd.Parameters.Add(new OracleParameter("Date", datarow["DATE"]))
cmd.Parameters.Add(new OracleParameter("Number", datarow["Number"]));
// cmd.CommandText = sqlqry; -- not necessary, handled in constructor
cmd.ExecuteNonQuery();
}
If not, maybe try explicit conversions with either the type or value:
Yuck:
cmd.Parameters.Add(new OracleParameter("Date", Convert.ToDateTime(datarow["DATE"])))
cmd.Parameters.Add(new OracleParameter("Number", Convert.ToDecimal(datarow["Number"])));
Better:
cmd.Parameters.Add(new OracleParameter("DATE", OracleDbType.Date,
datarow["DATE"], ParameterDirection.Input);
cmd.Parameters.Add(new OracleParameter("Number", OracleDbType.Decimal,
datarow["Number"], ParameterDirection.Input));
And if worse comes to worse, the bulletproof (although verbose) way to do it would be:
cmd.Parameters.Add(new OracleParameter("DATE", OracleDbType.Date));
cmd.Parameters.Add(new OracleParameter("Number", OracleDbType.Decimal));
cmd.Parameters[0].Value = datarow["DATE"];
cmd.Parameters[1].Value = datarow["Number"];
As a footnote, this last way is actually preferred if you have multiple rows to insert, as you create the parameters once and modify the values and execute the insert multiple times:
cmd.Parameters.Add(new OracleParameter("DATE", OracleDbType.Date));
cmd.Parameters.Add(new OracleParameter("Number", OracleDbType.Decimal));
foreach (DataRow datarow in datarows)
{
cmd.Parameters[0].Value = datarow["DATE"];
cmd.Parameters[1].Value = datarow["Number"];
cmd.ExecuteNonQuery();
}
-- EDIT --
Based on your feedback and my improved proofreading skills, this is what I'd recommend. I added a transaction in there for good measure:
string sqlqry = "insert into Table (Date,Number) values(:Date,:Number)";
OracleTransaction trans = conn.BeginTransaction(IsolationLevel.ReadCommitted);
OracleCommand cmd = new OracleCommand(sqlqry, conn, trans);
cmd.Parameters.Add(new OracleParameter("DATE", OracleDbType.Date));
cmd.Parameters.Add(new OracleParameter("Number", OracleDbType.Decimal));
foreach (DataGridViewRow datarow in this.dataGridView1.Rows)
{
cmd.Parameters[0].Value = datarow.Cells["DATE"].Value;
cmd.Parameters[1].Value = datarow.Cells["Number"].Value;
cmd.ExecuteNonQuery();
}
trans.Commit();
For what it's worth, you also need some exception handling.
You would probably want to use:
cmd.Parameters.Add(new OracleParameter(DbType.Date, datarow["DATE"]))
cmd.Parameters.Add(new OracleParameter(DbType.Double, datarow["Number"]));
Please see https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlparameter.dbtype(v=vs.110).aspx
I am sending ID as outparameter but its giving error
System.Data.SqlClient.SqlException: Procedure or function
'usp_ClientHistoryItem' expects parameter '#ID', which was not
supplied.
Code
using (SqlCommand cmd = new SqlCommand("dbo.usp_ClientHistoryItem", conn))
{
SqlParameter parameterID = new SqlParameter("#ID", oReservation.Id);
parameterID.Direction = ParameterDirection.Output;
cmd.Parameters.Add(parameterID);
cmd.Parameters.Add(new SqlParameter("#PhoneNo", oReservation.ClientPhone));
cmd.Parameters.Add(new SqlParameter("#UserId", oReservation.UserID));
cmd.Parameters.Add(new SqlParameter("#Description", oReservation.Description));
cmd.Parameters.Add(new SqlParameter("#TestId", oReservation.TestId));
cmd.Parameters.Add(new SqlParameter("#StartDate", oReservation.StartDate));
cmd.ExecuteNonQuery();
returnValue = Convert.ToInt32(cmd.Parameters["#ID"].Value);
return returnValue;
}
You seem to be calling a stored procedure - yet you've never defined your SqlCommand to be a stored procedure:
using (SqlCommand cmd = new SqlCommand("dbo.usp_ClientHistoryItem", conn))
{
cmd.CommandType = CommandType.StoredProcedure; // add this line to tell ADO.NET it's a stored procedure!!
If you forget that line, then ADO.NET will try to interpret your stuff as an ad-hoc SQL statement....
this one solve my problem
may be it may helpful
cmd.CommandType = CommandType.StoredProcedure;
Your ID parameter in the stored procedure must be set as OUTPUT parameter. You are just setting it in code not in stored procedure.
Hy guys.
You have to set the property CommandType for the Command to StoredProcedure if that's the case. Otherwise it woun't detect the parameters.
One other reason this error is thrown is when the variable names don't match in your stored procedure and code because the code fails to find the parameter to which the value must be passed. Make sure they match:
Stored procedure:
create procedure getEmployee
#ID
as
Begin
select *
from emp
where id = #ID
End
Code:
SqlParameter p = new SqlParameter("#ID", id);
cmd.Parameter.Add(p);
The parameter #ID must match in both code and stored procedure
If you use dapper, you can use this construction
int id = 1;
var parameters = new DynamicParameters();
parameters.Add("#id", id, DbType.Int32, ParameterDirection.Input);
string sqlQuery = "[dbo].[SomeStoredProcedure]";
using (IDbConnection db = new SqlConnection(ConnectionString))
{
var result = await db.QueryAsync<SpResult>(sqlQuery, parameters, commandType: CommandType.StoredProcedure);
}