I have this C# webform that has has a date picker box. If the date is set to nothing (the default) I want it to pass NULL to the database. This happens inside my parametrized query.
SqlParameter CMActionDate = new SqlParameter();
CMActionDate.ParameterName = "#ActionDate";
if (ActionDate.Equals(""))
{
CMActionDate.Value = System.Data.SqlTypes.SqlDateTime.Null;
}
else
{
CMActionDate.Value = ActionDate;
}
When I turn on debugging I see that the date is indeed "" so it goes into the IF statement and sets the actiondate.value to {Null} like I think it should.
However.
When it then goes to execute the nonquery, I click the magnifying glass and see this:
UPDATE table SET [action_date] = '' WHERE [id] = 2488
What I would like to see is this:
UPDATE table SET [action_date] = 'Null' WHERE [id] = 2488
Since the action_date never really gets set to NULL, then the value in the datetime field reverts to "01/01/1900 12:00:00AM" and that's a pain in itself.
I have tried setting CMActionDate.Value to the following values to no avail (I get the same result as above.):
DBNull.Value;
"NULL";
SqlDateTime.Null;
null;
Yes, of course the parametrized query looks like this:
"UPDATE CM_Codebase SET [action_date] = '" + #ActionDate + "' WHERE [id] = " + #CM_id + "";
But when I am debugging this thing in VS, I put a breakpoint right before ExecuteNonQuery(); so I can see the SQL it's trying to run. It's there that I see the actual SQL and see the bit where action_date=''.
You shouldn't see either '' or 'Null'. If you're using parameterized queries correctly it should look like this:
UPDATE table SET [action_date] = #ActionDate WHERE [id] = #ID
The whole point of a parameterized query is that the actual parameter value is never substituted directly into the query string.
Your query code should look something like this:
string sql = "UPDATE table SET [action_date]= #ActionDate WHERE [id]= #CM_id";
using (var cn = new SqlConnection("your connection string here."))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("#ActionDate", SqlDbTypes.DateTime).Value =
ActionDate.Equals("")? DBNull.Value : DateTime.Parse(ActionDate);
cmd.Parameters.Add("#CM_id", SqlDbTypes.Int).Value = 2488;
cn.Open();
cmd.ExecuteNonQuery();
}
The result of this code is that your query parameters are sent to the server as data. At no point in your C# code will you ever be able to view the query string with your data substituted in: it's sent to the server separately.
This prevents any possibility of the server executing a parameter value as code because of an error in sanitizing your parameter value. The data is completely separate, and doesn't need to be sanitized for that context in the first place. It also allows the server to cache and reuse the execution plan for the query, resulting in a (small) performance boost.
Your parametized query should show
UPDATE table SET [action_date] = #ActionDate WHERE [id] = #id
And the parameter value should have a null equivalent value.
Your sql is
"UPDATE CM_Codebase SET [action_date] = '" + #ActionDate + "'
WHERE [id] = " + #CM_id + "";
Which doesn't really make sense. You should let sql replace the #ActionDate and #CM_ID, not build a dynamic sql query.
Your sql should literally be:
String sql = "UPDATE table SET [action_date] = #ActionDate WHERE [id] = #CM_id"
There should be no string concatenation around the variables, and they should not be wrapped in quotes.
Your query most certainly does not look like the ones posted.
Your #parameter needs to be inside your string, in order to be read correctly. You are seeing ActionDate = '' because #ActionDate does not exist, most likely.
You need something like
string sql = "UPDATE CM_Codebase SET [action_date] = #ActionDate WHERE [id] = #CM_id";
Notice that there is no string concatenation taking place.
Related
Here's my code.
public void setUpdate(List<string> code, string tableName)
{
SQLiteConnection con = new SQLiteConnection(connection);
SQLiteCommand UPDATE = new SQLiteCommand("UPDATE #TableName SET #ColumnName = #Value WHERE Key = #PK", con);
UPDATE.Parameters.AddWithValue("#TableName", "TEST");
UPDATE.Parameters.AddWithValue("#ColumnName", code[1]);
UPDATE.Parameters.AddWithValue("#Value", code[2]);
UPDATE.Parameters.AddWithValue("#PK", code[0]);
using (con)
{
con.Open();
UPDATE.ExecuteNonQuery();
}
}
And I'm getting this exception
System.Data.SQLite.SQLiteException: 'SQL logic error
near "#TableName": syntax error'
I already tried using
UPDATE.Parameters.Add(new SQLiteParameter("#TableName", DbType.String) .Value = tableName);
Still getting the same exception.
I don't know anymore how to solve this.
I don't wanna use the concatenation because it screws up the query when you pass a value like the one below.
Smith's
EDIT:
I placed a breakpoint on
using (con)
Then checked the commandText. The result is:
"UPDATE #TableName SET #ColumnName = #Value WHERE Key = #PK"
I think there is the problem with table name as a parameter.
So firstly try to left all parameters except of table name (hardcode 'TEST' into query temporarily) and if it works take a look on this:
C# query with dynamic tablename
Again, trying to build a query with from and column names you can't do as PARAMETER. They need to be fixed in the string. BUT CAUTION. DO NOT Allow the table/column/etc parts that you build come from an untrusted source, especially the web for damage of SQL-Injection.
If your system is controlling the origin AND QUALIFIED, or otherwise internally control the table name being passed in, AND you control / qualify the column name being passed in, I would adjust your function as follows:
public void setUpdate(List<string> code, string tableName)
{
SQLiteConnection con = new SQLiteConnection(connection);
SQLiteCommand UPDATE = new SQLiteCommand(
"UPDATE " + tableName + " set " + code[1] + " = #Value WHERE Key = #PK", con);
UPDATE.Parameters.AddWithValue("#Value", code[2]);
UPDATE.Parameters.AddWithValue("#PK", code[0]);
using (con)
{
con.Open();
UPDATE.ExecuteNonQuery();
con.Close();
}
}
Again, this is on the premise that YOU are controlling and sanitizing the origins of the tableName parameter, and your code array, second element via [1] representing the column name. The setting value EQUAL TO and where key EQUALS are ok for parameters.
And if that does not work, I would start with a query that you know is legit/clear just to TEST the functionality with parameters.
"UPDATE YourTable set YourColumn = #Value WHERE Key = #PK"
I am having issues when trying to get the result of an updated row, the query that I use as shown below update a certain row when it meets a specific conditions,however, and though the conditions are not met, the Update query output gets the value "0" rather than NULL, Is there any tips so that I can fix this in the same query,with that said, I'm trying to avoid the use of other queries because it's within a method that has to optimised the most possible.
SqlCommand loadbonus = new SqlCommand();
loadbonus.Connection = conn;
loadbonus.CommandText = "UPDATE Client SET [Restant Bonus]=[Restant Bonus]-(SELECT SUM([Prix Total]) FROM Comptoir WHERE [N° Comptoir]='" + tabcontrol.SelectedIndex + "'),[Total Consommé]=[Total Consommé]+(SELECT SUM([Prix Total]) FROM Comptoir WHERE [N° Comptoir]='" + tabcontrol.SelectedIndex + "') OUTPUT INSERTED.[Restant Bonus] WHERE [Code Client]=#CodeClient AND [Bonus Fidélité]='1'";
loadbonus.Parameters.Add("#CodeClient", SqlDbType.Int).Value = string.IsNullOrWhiteSpace(clientcodecomptoire.Text) ? DBNull.Value : (object)Convert.ToInt32(clientcodecomptoire.Text);
int restantbonus = Convert.ToInt32(loadbonus.ExecuteScalar());
if (restantbonus <= 0)
{// here is the issue! the left side of the If statement can containt there "0" value for both a "0" value and a Null value}
Using a stored procedure has many benefits. It starts to get you a separate data layer from the application. It is also parameterized so you can avoid sql injection.
Here is what your procedure might look like.
create procedure Client_Update
(
#NComptoir int
) as
set nocount on;
declare #MyTotal int;
SELECT #MyTotal = SUM([Prix Total])
FROM Comptoir
WHERE [N° Comptoir] = #NComptoir;
UPDATE Client
SET [Restant Bonus] = [Restant Bonus] - #MyTotal
,[Total Consommé] = [Total Consommé] + #MyTotal;
select #MyTotal;
Then to use in dotnet you should change up a few things. You need to use the USING statement around objects like commands and connections to ensure they get properly disposed of. You already have a connection object so I am leaving that to you.
using (SqlCommand loadbonus = new SqlCommand("Client_Update", conn))
{
loadbonus.CommandType = CommandType.StoredProcedure;
loadbonus.Parameters.Add("#NComptoir", SqlDbType.Int).Value = tabcontrol.SelectedIndex;
int restantbonus = Convert.ToInt32(loadbonus.ExecuteScalar());
if (restantbonus <= 0)
{
}
}
The issue I see though is that you add a parameter (#Seuil) in your code but it is not part of the update statement. And since you are setting the value to the text of a textbox it will get 0 when set to an empty string. That is because it is being converted to an int. I have no idea what the purpose of that parameter is though because it is not part of your query.
I hope this helps at least give you a push in the right direction.
I'm having problems with some code I'm trying to write. I'm doing something for suppliers orders, so I have a table which is named "encomendas_fornecedores" with a autoincrement field before the key that is the code of sale which consists in a EF before the number(which is a text field).
Here is the code:
connection.Open();
OleDbCommand comando1 = new OleDbCommand();
OleDbCommand comando2 = new OleDbCommand();
OleDbCommand comando3 = new OleDbCommand();
comando1.Connection = connection;
comando2.Connection = connection;
comando3.Connection = connection;
comando1.CommandText = "INSERT INTO encomendas_fornecedores (cod_encomenda_forn, cod_metodo, cod_forn, total_pagar_forn) VALUES('FO', '" + txtcodmetodo.Text + "', '" + txtcodforn.Text + "', '" + lbltotalapagar.Text + "'); ";// insert into table the values with a FO to cod
comando1.ExecuteNonQuery();
comando2.CommandText = "Select MAX(num_encomenda) From encomendas_fornecedores;";// selecting maximum num encomenda so I can isolate it and add to a text before(btw I do this in php/sql no problems
int numero = Convert.ToInt32(comando2.ExecuteScalar());//max num_encomenda
string codencomendaforn= "EF"+Convert.ToString(numero);// sales code completed
comando3.CommandText = "UPDATE encomendas_fornecedores SET cod_encomenda_forn = '"+codencomendaforn+"' WHERE num_encomenda = '"+ numero +"';";//query that is giving me the problems, it says something like "type of data incorrect in data expression"
comando3.ExecuteScalar();//giving me error this line
connection.Close();
But now here's the catch the cod_encomenda_forn is text and the num_encomenda auto increment as it is in the sql, and I tried to show the query in a textbox to see if its anything is wrong but nothing seems wrong.
"UPDATE encomendas_fornecedores SET cod_encomenda_forn = '"+codencomendaforn+"' WHERE num_encomenda = **'**"+ **numero** +"**'**;";//query that is giving me the problems,it says something like "type of data incorrect in data expression"
You are passing a string numero to a where statement that seems like it is expecting a number. As long as it is numeric it should work, but definitely not gauranteed to work. Second you are passing anothercodencomendaforn string to encomenda what is encomenda 's data type?
It appears that you are not handling potential datatype differences between your c# code and your SQL query. In addition single quoting '' around a value in a SQL statement tells the database engines that it is a string even if that is '1234'. While SQL will automatically convert some values it doesn't always. In addition c# .net library also looks for some conversion etc. before sending the SQL statement. To fix appropriately use parameters that are data typed to the database type in the SQL table. To fix it simply in the statement figure out your data types and fix the '' single quotes appropriately.
PS the people trying to help you in the comments were being nice and telling you the professional way of keeping your job in the future when you graduate after fixing this issue.
Ok been starring at this for a good while and i can not under stand why it is not updating my database..... I do not get an error messages it runs just fine. Code below
if (e.KeyCode == Keys.Enter)
{
// #WORK
string searchtext = txtAssetScanned.Text;
string searchcmd = "UPDATE " + lstCompCode.SelectedItem.ToString() + " SET " + lstCompCode.SelectedItem.ToString() + ".[Inventory Status]= \"FOUND\" WHERE [Inventory number] like '*" + searchtext + "';";
MessageBox.Show(searchcmd);
myConnection.Open();
OleDbCommand search = new OleDbCommand();
search.Connection = myConnection;
search.CommandText = searchcmd;
search.ExecuteNonQuery();
myConnection.Close();
}
There are a few things that pop out here :
Use Parameterized Queries. You should be using parameterized queries, concatenating in the manner you currently are can cause syntax issues and leave you vulnerable to SQL Injection.
Consider Using Single Quotes for Values. When setting string values in SQL, you should use single quotes 'value' as opposed to double quotes (i.e. "value").
SelectedValue over SelectedItem. Consider using the SelectedValue property as opposed to SelectedItem.ToString() to ensure you use the proper value.
Table Names as Parameters May Not Be Allowed. If you are using a table name as a parameter, which in many cases may be flat out rejected (as they are generally reserved for values), so fair warning.
Double-check for Typos. Finally, ensure the properties that you are targeting are correct and do not contain any typos (i.e. Foo.[Inventory number], etc.)
You can apply these changes as follows :
using(var connection = new OleDbConnection("{your-connection-string}"))
{
// Build your query with parameters
var query = "UPDATE ? SET [Inventory Status] = 'FOUND' WHERE [Inventory number] LIKE ?";
using(var command = new OleDbCommand(query, connection))
{
connection.Open();
// Add your parameters
command.Parameters.AddWithValue("#table",lstCompCode.SelectedValue);
command.Parameters.AddWithValue("#search", "*" + txtAssetScanned.Text);
// Now that your queries are added, perform your update
command.ExecuteNonQuery();
}
}
The Likely Issue
As I mentioned, some databases will not allow you to pass in table names as parameters without resorting to stored procedures, dynamic SQL, etc. You may be better off simply defining the table that you want to use directly :
var query = "UPDATE [YourTableName] SET [Inventory Status] = 'FOUND' WHERE [Inventory number] LIKE ?";
Since you cannot pass this through via parameters, you might consider adding some logic to determine which to use and hard-code it along with some sanitation to avoid possible nefarious behavior.
I have the following code in asp.net:
using (OleDbCommand command = dbConnW.CreateCommand())
{
string CreateTableK = null;
CreateTableK += "Create Table DSKKAR00 (DSK_ID c(10),DSK_KIND N(1),MON_PYM C(3))";
OleDbCommand cmdCreateTable = new OleDbCommand(CreateTableK, dbConnW);
cmdCreateTable.ExecuteNonQuery();
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append(WorkRoomNo + ",");
sb.Append("1,");
sb.Append(",");
OleDbCommand cmd3 = new OleDbCommand("Insert into DSKKAR00 (DSK_ID,DSK_KIND,MON_PYM) Values (" + sb.ToString() + ")", dbConnW);
cmd3.ExecuteNonQuery();
But I have the following error:
Syntax error
In addition to what Chris has offered, you are starting your CREATE TABLE with a NULL string variable, then doing a += to it. From what I remember, a NULL += "anystring" will remain a null value... You might be crashing right there too.
Although VFP is not really suceptible to SQL Injection like other SQL engines, its good habit to do parameterizing. When you do, use "?" as a place-holder for the value you want to insert, and add parameters in the same order sequence as the "?" represent.
string CreateTableK =
"Create Table DSKKAR00 (DSK_ID c(10),DSK_KIND N(1),MON_PYM C(3))";
OleDbCommand cmdCreateTable = new OleDbCommand(CreateTableK, dbConnW);
cmdCreateTable.ExecuteNonQuery();
string MyInsert =
"insert into DSKKAR00 ( dsk_id, dsk_kind, mon_pym ) values ( ?, ?, ? )";
OleDbCommand cmd3 = new OleDbCommand( MyInsert, dbConnW);
cmd3.Parameters.AddWithValue( "parmSlot1", WorkRoomNo );
cmd3.Parameters.AddWithValue( "parmSlot2", 1);
cmd3.Parameters.AddWithValue( "parmSlot3", 'tst' ); // or whatever variable to put
cmd3.ExecuteNonQuery();
First off, any time you have an error it's usually best to post the entire error message you get.
Also, when trying to debug a query problem, you should emit the actual query being sent to your server/database and inspect it. This way you can find various problems like too many commas.
Speaking of which, looking at your code, you are concatenating a String and it really looks like you have way too many commas.
The emitted query looks like it will be:
insert into DSKKAR00(DSK_ID, DSK_KIND, MON_PYM) VALUES( X,1, ,)
where X is the value of your WorkRoomNo variable.
Obviously, that isn't valid syntax and would result in the error you've seen. The commas indicate there are 4 values being passed, but the insert query only identifies 3 columns.
The next issue has to do with the column definitions themselves. The first column of that table is a c(10); the third is a c(3). I'm a little rusty, but aren't those character fields?
If so then you need to adjust your string builder to add the appropriate quotes around the values...
Which leads us to the final problem: Don't use String concatentation to build queries. Use Parameterized queries