I am trying to get an insert/return primary key SQL query to run.
The query ends up looking like this:
declare #userid as integer;
insert into users (username,emailaddress,passwordhash,salt) values
(#username,#email,#password,#salt);
set #userid=scope_identity();
insert into groups (name,userid) values ('somegroup',#userid);
select #userid;
This simply goes into the SqlCommand.CommandText field. So this is executed as a single query
I then add the parameters like this: (cmd is a SqlCommand object)
cmd.Parameters.Add(new SqlParameter("#email",user.EmailAddress));
cmd.Parameters.Add(new SqlParameter("#username",user.Username));
cmd.Parameters.Add(new SqlParameter("#salt",user.Salt));
cmd.Parameters.Add(new SqlParameter("#password", user.PasswordHash));
I then execute the query with ExecuteScalar(); It will throw an error at this point though saying the parameter #email doesn't exist.
How do I fix this problem?
I've figured it out. If you send give null as the value of a parameter, it won't actually be added. So the solution(for me anyway, for you, it may involve DBNull) was to convert nulls into empty strings as so:
cmd.Parameters.Add(new SqlParameter("#email",user.EmailAddress ?? ""));
cmd.Parameters.Add(new SqlParameter("#username",user.Username));
cmd.Parameters.Add(new SqlParameter("#salt",user.Salt ?? ""));
cmd.Parameters.Add(new SqlParameter("#password", user.PasswordHash ?? ""));
You must prefix all parameter names with an #, so this will work:
cmd.Parameters.Add(new SqlParameter("#email",user.EmailAddress));
using (TransactionScope scope = new TransactionScope())
{
//Your code should be here in this case, as you are not using SP.
//So this will help you in case of multiple users
)
Or
Commit/Rollback Transaction
Related
I am getting this error while trying to update but I am not able to find any issue in update statement.
str = "UPDATE BillTable SET Bill_No = #billno, Bill_Year = #billYear, Voucher_No= #voucher, Date= #date, Group_ID= #groupname, Vendor_Id= #vendorname, Amount= #amount WHERE ID= #billID";
cmd = new OleDbCommand(str, cn);
cmd.Parameters.Add(new OleDbParameter("#billID", Convert.ToString(inovidid)));
cmd.Parameters.Add(new OleDbParameter("#billYear", Convert.ToString(fylabel.Text)));
cmd.Parameters.Add(new OleDbParameter("#billno", Convert.ToString(billno.Text)));
cmd.Parameters.Add(new OleDbParameter("#voucher", Convert.ToString(voucher.Text)));
cmd.Parameters.Add(new OleDbParameter("#date", Convert.ToString(DateTimePicker1.Text)));
cmd.Parameters.Add(new OleDbParameter("#groupname", Convert.ToString(groupidDB)));
cmd.Parameters.Add(new OleDbParameter("#vendorname", Convert.ToString(vendoridDB)));
cmd.Parameters.Add(new OleDbParameter("#amount", Convert.ToString(amount.Text)));
Conversion to string as well as out of order parameters may eventually cause a "data type mismatch" error or simply failure to execute (OleDbCommand parameters order and priority) but syntax error is most likely caused by use of Date as a field name. Date is a reserved word (intrinsic function). It even causes error with Execute command in Access VBA. Either rename the field or enclose in [ ] to define as field name: [Date]=#date.
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 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.
This question already has answers here:
Assign null to a SqlParameter
(20 answers)
Closed 7 years ago.
I'm trying to execute this command but get an exception:
cmd.CommandText = #"insert into Foo (Column1, Column2)
values (#Parameter1, #Parameter2)";
cmd.Parameters.Add(new SqlParameter("#Parameter1", 'bar'));
cmd.Parameters.Add(new SqlParameter("#Parameter2", null));
The exception states that #Parameter2 is expected but was not supplied.
Actually I'm providing it with null value. So how can I insert this very null into nullable Column2?
If you want to provide a NULL to the underlying database, use DBNull.Value:
cmd.Parameters.Add("#Parameter2", SqlDbType.Int).Value = DBNull.Value;
Adapt to whatever datatype your parameter really is (I'm just guessing here, since you didn't tell us - and I prefer to always explicitly tell the parameter what datatype it is)
Use DBNull.Value to represent a null value to the database:
cmd.CommandText = #"insert into Foo (Column1, Column2)
values (#Parameter1, #Parameter2)";
cmd.Parameters.Add(new SqlParameter("#Parameter1", 'bar'));
cmd.Parameters.Add(new SqlParameter("#Parameter2", DBNull.Value));
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