I'm trying to add values from a textbox into a datagridview, I have asked this question before but I'm now getting a different error saying
There are more columns in the INSERT statement than values specified in the VALUES clause. The number of values in the VALUES clause must match the number of columns specified in the INSERT statement.
This is the code causing the error
private void SaveBtn_Click(object sender, EventArgs e)
{
SqlConnection sc = new SqlConnection();
SqlCommand com = new SqlCommand();
sc.ConnectionString = ("Data Source=localhost;Initial Catalog=LoginScreen;Integrated Security=True");
sc.Open();
com.Connection = sc;
com.CommandText = ("INSERT INTO Stock (Prod_ID, Prod_Name, Prod_Cat, Supplier, Cost, Price_1, Price_2, Price_3) VALUES ('"+ProdID.Text+"''"+ProdName.Text+"'+'"+ProdCat.Text+"'+'"+ProdSup.Text+"'+'"+ProdCost.Text+"'+'"+ProdPrice1.Text+"'+'"+ProdPrice2.Text+"'+'"+ProdPrice3.Text+"');");
com.ExecuteNonQuery();
sc.Close();
}
my database
The direct cause of the error is omitted commas (",") in the "value" section of the query.
You should have put it like that
VALUES ('"+ProdID.Text+"', '"+ProdName.Text+", '+'"+ProdCat.Text+", '+'"+ProdSup.Text+...
instead of
VALUES ('"+ProdID.Text+"''"+ProdName.Text+"'+'"+ProdCat.Text+"'+'"+ProdSup.Text+...
Your code is also vulnerable to so called SQL-injection attack (imagine someone has put
'" delete from Stock --' into ProdID.Text: the execution'll result in Stock table
clearance)
The recommended way looks something like this:
using(SqlConnection sc = new SqlConnection()) {
sc.ConnectionString = "Data Source=localhost;Initial Catalog=LoginScreen;Integrated Security=True";
sc.Open();
using (SqlCommand com = sc.CreateCommand()) {
com.CommandText =
"insert into Stock(\n" +
" Prod_Id,\n" +
" Prod_Name,\n" +
" Prod_Cat,\n" +
" Supplier,\n" +
" Cost,\n" +
" Price_1,\n" +
" Price_2,\n" +
" Price_3)\n" +
"values(\n" +
" #prm_Prod_Id,\n" +
" #prm_Prod_Name,\n" +
" #prm_Prod_Cat,\n" +
" #prm_Supplier,\n" +
" #prm_Cost,\n" +
" #prm_Price_1,\n" +
" #prm_Price_2,\n" +
" #prm_Price_3)";
//TODO: Change my arbitrary "80" to actual Stock fields' sizes!
com.Parameters.Add("#prm_Prod_Id", SqlDbType.VarChar, 80).Value = ProdID.Text;
com.Parameters.Add("#prm_Prod_Name", SqlDbType.VarChar, 80).Value = ProdName.Text;
com.Parameters.Add("#prm_Prod_Cat", SqlDbType.VarChar, 80).Value = ProdCat.Text;
com.Parameters.Add("#prm_Supplier", SqlDbType.VarChar, 80).Value = ProdSub.Text;
com.Parameters.Add("#prm_Cost", SqlDbType.VarChar, 80).Value = ProdCost.Text;
com.Parameters.Add("#prm_Price_1", SqlDbType.VarChar, 80).Value = ProdPrice1.Text;
com.Parameters.Add("#prm_Price_2", SqlDbType.VarChar, 80).Value = ProdPrice2.Text;
com.Parameters.Add("#prm_Price_3", SqlDbType.VarChar, 80).Value = ProdPrice3.Text;
com.ExecuteNonQuery();
}
}
You are missing commas in your values part of your sql. When ever you are doing something like this (big concatination of a string) you should know two things. First, a good way to test is to write out to console, messagebox, ext. You often will see the error right away. The next thing to know is that if you are concatintating to insert into a DB, dont do it. Use parameterized queries. -> How do parameterized queries help against SQL injection?
com.CommandText = ("INSERT INTO Stock (Prod_ID, Prod_Name, Prod_Cat, Supplier, Cost, Price_1, Price_2, Price_3) VALUES ('"+ProdID.Text+"''"+ProdName.Text+"'+'"+ProdCat.Text+"'+'"+ProdSup.Text+"'+'"+ProdCost.Text+"'+'"+ProdPrice1.Text+"'+'"+ProdPrice2.Text+"'+'"+ProdPrice3.Text+"');");
should be something like this
com.CommandText = (#"INSERT INTO Stock (Prod_ID, Prod_Name, Prod_Cat, Supplier, Cost, Price_1, Price_2, Price_3) VALUES ('"+ProdID.Text+"','"+ProdName.Text+"','"+ProdCat.Text+"','"+ProdSup.Text+"','"+ProdCost.Text+"','"+ProdPrice1.Text+"','"+ProdPrice2.Text+"','"+ProdPrice3.Text+"');"));
Checkbox values in a form either result in nothing whatsoever if no boxes are checked, or a comma delimted list of values. The worst thing you can possibly do is to store this list in a single record. That would result in unusable data.
Instead, you want to change not only your code, but possible your database design so that you have a single record for every box that was checked. Remember to account for the scenario where no boxes are checked.
Try :
com.CommandText = ("INSERT INTO Stock (Prod_ID, Prod_Name, Prod_Cat, Supplier, Cost, Price_1, Price_2, Price_3) VALUES ('"+ProdID.Text+"','"+ProdName.Text+"','"+ProdCat.Text+"','"+ProdSup.Text+"','"+ProdCost.Text+"','"+ProdPrice1.Text+"','"+ProdPrice2.Text+"','"+ProdPrice3.Text+"');");
You should Replace
('"+ProdID.Text+"''"+ProdName.Text+"'+'"+ProdCat.Text+"'+'"+ProdSup.Text+"'+'"+ProdCost.Text+"'+'"+ProdPrice1.Text+"'+'"+ProdPrice2.Text+"'+'"+ProdPrice3.Text+"');");`
with
('"+ProdID.Text+"','"+ProdName.Text+"','"+ProdCat.Text+"','"+ProdSup.Text+"','"+ProdCost.Text+"','"+ProdPrice1.Text+"','"+ProdPrice2.Text+"','"+ProdPrice3.Text+"');");`
(VALUES part needs commas for each column)
Related
I am not sure if this question already has answers on SO, but as I couldn't find one, I am writing here. I am trying to write an update query using CASE statement. The values of WHEN and THEN comes from user-given data where I need to update multiple rows with multiple values that the user gives. I am eliminating the loop that I have written in the original code in the snippet below as the problem is only with AddWithValue. Is there a way to use SqlParameterCollection to assign the THEN value? Or is a simple string concatenation a way to do this?
SqlCommand command = new SqlCommand("UPDATE [Table] SET Column = CASE ", connection);
command.CommandText += "WHEN Column = #Column1 THEN #Column2";
command.CommandText += "ELSE Column END";
command.Parameters.AddWithValue("#Column1", "Value1");
command.Parameters.AddWithValue("#Column2", "Value2");
connection.Open();
command.ExecuteNonQuery();
The error:
Incorrect syntax near '#Column2'
Just wanted to note that this syntax error probably also wouldn't have occurred if you'd used verbatim strings:
new SqlCommand(#"
UPDATE [Table]
SET
Column = CASE
WHEN Column = #Column1 THEN #Column2
ELSE Column
END"
, connection);
I tend to stick all the sql so it starts from indent level 0, and using the # string means it can be formatted how I like an sql to be without any interim c# making it messy.
If you're building a variable number of cases, string interpolation might also tidy things up and you can have an interpolated # string by prefixing $# - I remember which way round they go by "Microsoft are polite and didn't want to fill people's code with #$ (ass)" ;)
var whens = "WHEN...";
for(...){
whens += ...
parameters.Add(..)
}
new SqlCommand($#"
UPDATE [Table]
SET
Column = CASE
{whens}
ELSE Column
END
", connection);
And of course final debugging tip; if you build an sql dynamically and you get a syntax error, pause in the debugger and look at the command text just before you run it; point to the Command variable, open the tooltip, click the magnifying glass next to CommandText property to see the string as is in a notepad style window, with new lines etc as actual new lines not as \n that the debug tooltip shows - it's a lot easier to spot syntax errors in this visualizer
image courtesy of https://gunnarpeipman.com/ef-core-toquerystring/amp/
So finally it's all about the syntax errors as mentioned by #marc_s and #serg in the comments. This worked:
SqlCommand command = new SqlCommand("UPDATE [Table] SET Column = CASE ", connection);
command.CommandText += "WHEN Column = #Column1 THEN #Column2 ";
command.CommandText += "ELSE Column END";
command.Parameters.AddWithValue("#Column1", "Value1");
command.Parameters.AddWithValue("#Column2", "Value2");
connection.Open();
command.ExecuteNonQuery();
Try the following SQL Server code:
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.Parameters.AddWithValue("#Column1", "Value1");
command.Parameters.AddWithValue("#Column2", "Value2");
String StrSqlCommand = "UPDATE [Table] SET Column = CASE ";
StrSqlCommand += " WHEN Column = #Column1 THEN #Column2 ";
StrSqlCommand += " ELSE Column END ";
command.CommandText = StrSqlCommand;
connection.Open();
command.ExecuteNonQuery();
Also be careful about the terms "Value1" and "Value2". Because in the code you send, the above values are considered exactly the same as the string type. If you want another value, it is better to define a variable and put it as a parameter in the above expressions. Something like this:
String strValue1 = "Name1";
String steValue2 = "Name2";
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.Parameters.AddWithValue("#Column1", strValue1);
command.Parameters.AddWithValue("#Column2", strValue2);
String StrSqlCommand = "UPDATE [Table] SET Column = CASE ";
StrSqlCommand += " WHEN Column = #Column1 THEN #Column2 ";
StrSqlCommand += " ELSE Column END ";
command.CommandText = StrSqlCommand;
connection.Open();
command.ExecuteNonQuery();
This is my first time creating a web api from scratch and I'm trying to get a selected value in a drop down bow to trigger an sql search and make the appropriate item appear in a text box. below is the relevant code
protected void btnRetrieve_Click(object sender, EventArgs e)
{
try
{
string pNameTemp = DropDownList1.SelectedValue;
myConnection.Open();
string query = ("SELECT sName from [dbo].[Table] WHERE (pName LIKE " + pNameTemp + ")");
SqlCommand sqlCmd = new SqlCommand(query, myConnection);
txtSkill.Text = sqlCmd.ExecuteScalar().ToString();
myConnection.Close();
}
catch(Exception ex)
{
throw new Exception(ex.Message);
}
}
it seems to search the correct name but when it comes to updating the txtSkill, I get the exception 'invalid column name' pop up, are there any obvious reasons as to why this is happening that i'm missing? any advice would be appreciated
In fact, you are missing '' for the parameter of the query.
Try to use this query.
SqlCommand sqlCmd = new SqlCommand(#"SELECT sName from [dbo].[Table] WHERE pName LIKE '{pNameTemp}'", myConnection);
But I recommend you to use SqlParameter in C# to avoid SQL Injection
SqlCommand com = new SqlCommand("SELECT sName from [dbo].[Table] WHERE pName LIKE #field", myConnection);
myConnection.Parameters.AddWithValue("#field", pNameTemp);
But normally, when we use LIKE, we should put in % because it gives all results contains keyword. LIKE without % doesn't make sense. So :
SqlCommand com = new SqlCommand("SELECT sName from [dbo].[Table] WHERE pName LIKE #field", myConnection);
command.Parameters.AddWithValue("#field", "'%" + pNameTemp + "%'");
There are some options in the LIKE clause:
%: The percent sign represents zero, one, or multiple characters
_ The underscore represents a single character
I'm using a a multiple query with insert and update statement together.
The problem is that if query will not be completed(for some reason e.x bad internet connection) my SQL Server table keeps rubbish.
Example of query:
SqlCommand cmd = new SqlCommand("INSERT INTO CustomerTrans (TableName, UserID, UserName, SumQuantity, SumPrice, SumRealPrice, SumExtrasPrice, SumTotal, SumDiscountTotal, DateTime) SELECT " + Connection.TableName + ",' " + Connection.UserID + "', '" + Connection.Username + "',Sum(Quantity),Sum(Price),Sum(RealPrice),Sum(ExtrasPrice), Sum(Quantity * Price),Sum(Quantity * DiscountPrice),'" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' from InventoryTransTemp where active=1 and TableName=" + Connection.TableName + ";update InventorytransTemp set TrnDocumentID=(select max(TrnDocumentID) from CustomerTrans where UserID='" + Connection.UserID + "'),Active=0 where TableName=" + Connection.TableName + " and Active=1", con);
cmd.ExecuteNonQuery();
Take a photo from a query which has not be completed properly look query 2989 it has NULL values. I want to avoid inserting something if query is not be completed properly.
Sorry for my previous Question it was Unclear
Try it like this:
string sql =
"INSERT INTO CustomerTrans" +
" (TableName, UserID, UserName, SumQuantity, SumPrice, SumRealPrice, SumExtrasPrice, SumTotal, SumDiscountTotal, DateTime)" +
" SELECT #TableName, #UserID, #Username, Sum(Quantity), Sum(Price), Sum(RealPrice), Sum(ExtrasPrice), Sum(Quantity * Price), Sum(Quantity * DiscountPrice), current_timestamp" +
" FROM InventoryTransTemp" +
" WHERE active=1 and TableName= #TableName;\n" +
"SELECT #TranID = scope_identity;\n"
"UPDATE InventorytransTemp" +
" SET TrnDocumentID=#TranID ,Active=0" +
" WHERE TableName= #Tablename and Active=1;";
using (var con = new SqlConnection("connection string here"))
using (var cmd = new SqlCommand(sql, con))
{
//I'm guessing at exact column types/lengths here.
// You should update this to use your exact column types and lengths.
// Don't let ADO.Net try to guess this for you.
cmd.Parameters.Add("#TableName", SqlDbType.NVarChar, 20).Value = Connection.TableName;
cmd.Parameters.Add("#UserID", SqlDbType.Int).Value = Connection.UserID;
cmd.Parameters.Add("#Username", SqlDbType.NVarChar, 20).Value = Connection.Username;
cmd.Parameters.Add("#TranID", SqlDbType.Int).Value = 0; //placeholder only
con.Open();
cmd.ExecuteNonQuery();
}
Note the improved formatting of the query, the use of scope_identity() to get the new identity value rather than a nested select statement that might not be atomic, that I avoided ALL uses of string concatenation to substitute data into the query, that I avoided the AddWithValue() method entirely in favor of an option that doesn't try to guess at your parameter types, and the use of using blocks to be sure the SqlClient objects are disposed properly.
The only thing I'm still concerned about is if your INSERT/SELECT operation might create more than one new record. In that case, you'll need to handle this a different way that probably involves explicit BEGIN TRANSACTION/COMMIT statements, because this code only gets one #TranID value. But in that case, the original code was broken, too.
I have problem with the query to delete a row from table(I am using MySQL lite), I'm using data bound comobox to select what to delete but I get this error {"Invalid column name 'Football'."} on executing the command
con.Open();
SqlCommand cm = new SqlCommand("DELETE FROM Sports WHERE Sport = " + cbSelectSport.Text + "", con);
cm.ExecuteNonQuery();
MessageBox.Show("Done");
con.Close();
String concatenation should be avoided in almost every case. You should use parameterized queries whenever possible. You avoid conversions, SQL injection attacks and the code is typically faster because the server can reuse execution plans
Writing a parameterized query is also easier:
using(var con=new SqlConnection(...))
{
con.Open();
var cm = new SqlCommand("DELETE FROM Sports WHERE Sport = #sports", con);
var parameter=cm.Parameters.AddWithValue("#sports",cbSelectSport.Text);
cm.ExecuteNonQuery();
MessageBox.Show("Done");
};
This way the parameter values are passed out of band (ie outside the query) without converting to text. This is extremely useful when you want to pass decimal or date values.
Most people would warn against using AddWithValue because it makes too many assumptions based on its input value that can hurt performance. In this case you can use Add to create the parameter, then set its value, size, precision etc:
var parameter=cm.Parameters.Add("#sports",SqlDbType.NVarChar);
parameter.Size=20;
parameter.Value=cbSelectSport.Text;
Be careful with you syntax.
I don't know the type of the sport column, but I think need to enclose your value in quotes( single or double).
new SqlCommand("DELETE FROM Sports WHERE Sport = \"" + cbSelectSport.Text + "\", con);
or
new SqlCommand("DELETE FROM Sports WHERE Sport = '" + cbSelectSport.Text + "', con);
You must specify textvalue in single quotation marks ''.
SqlCommand cm = new SqlCommand("DELETE FROM Sports WHERE Sport = '" + cbSelectSport.Text + "'", con);
You might want to add the single quote:
SqlCommand cm = new SqlCommand("DELETE FROM Sports WHERE Sport = '" + cbSelectSport.Text + "'", con);
You should use parametrized query to prevent SQL Injection attack. Also it will solve your problem. By the way you can just add single quotes to your query.
"DELETE FROM Sports WHERE Sport = '" + cbSelectSport.Text + "'"
I'm developing an ASP.NET MVC Web Application using SQL Server.
I am trying to INSERT a new entry into my database and I don't understand what am I doing wrong.
I get an exception on the line:
command.ExecuteNonQuery();
The code is:
try
{
SqlConnection connection = new SqlConnection(#"Data Source=.\SQLEXPRESS;Initial Catalog=UniversityManager;Integrated Security=True");
using (connection)
{
//SqlCommand command = new SqlCommand(
// "INSERT INTO Students VALUES(#Id, #Name, #Surname, #Year, #PhoneNumber, #Cnp);",
// connection);
connection.Open();
String sql = "INSERT INTO Students(Id,Name,Surname,Year,PhoneNumber,Cnp) " +
"VALUES (#Id, #Name, #Surname, #Year, #PhoneNumber, #Cnp)";
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.Add("#Id", SqlDbType.Int);
command.Parameters["#Id"].Value = 5;
command.Parameters.Add("#Name", SqlDbType.VarChar);
command.Parameters["#Name"].Value = collection.Name;
command.Parameters.Add("#Surname", SqlDbType.VarChar);
command.Parameters["#Surname"].Value = collection.Surname;
command.Parameters.Add("#Year", SqlDbType.Int);
command.Parameters["#Year"].Value = collection.Year;
command.Parameters.Add("#PhoneNumber", SqlDbType.VarChar);
command.Parameters["#PhoneNumber"].Value = collection.PhoneNumber;
command.Parameters.Add("#Cnp", SqlDbType.VarChar);
command.Parameters["#Cnp"].Value = collection.Cnp;
command.ExecuteNonQuery();
connection.Close();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Thank you!
YEAR is a reserved keyword for Sql Server. So, if you really have a column with that name, then you need to enclose it in square brackets every time you refer to it. Better change that name
String sql = "INSERT INTO Students(Id,Name,Surname,[Year],PhoneNumber,Cnp) " +
"VALUES (#Id, #Name, #Surname, #Year, #PhoneNumber, #Cnp)";
Another possibility is the Id column. If this column has the IDENTITY property set to true, then you should not set a value for it. It is automatically calculated by the database engine.
Looking at your innerexception message, it seems the problem is due to one or more of your parameters contains more text than allowed by the database field size.
You could try something like this (for each varchar parameter)
// Assuming the Name field is defined as varchar(15)
command.Parameters.Add("#Name", SqlDbType.VarChar, 15);
command.Parameters["#Name"].Value = collection.Name;
The String or binary data would be truncated exception means you're trying to insert a value that is too large for one of the columns in your Student table. For example, your Name field has a maximum length of 10 but you're trying to insert a 15 character name.
Check the values you're inserting and see if they're too large for the columns.