miscalculation in update sql query - c#

string queryString4 = "UPDATE Table1 SET currentMoney =currentMoney + '" + money + "'WHERE accountNo='" + recipientNo + "';";
user1 & user2 have $100
user1 transfer $5 to user2.
user1 now have $95 & user2 now have $1005
Somehow it did not calculate properly. Im suspecting the code above because I did a querystring3 which is minus instead of a plus and it works. However querystring4 is a bit of a problem.

You're appending a string here:
currentMoney =currentMoney + '" + money + "'
Let's assume that money is 5, this becomes:
currentMoney =currentMoney + '5'
In many languages this will result in an implicit conversion of the numeric value to a string value, so:
100 + '5' = '1005'
Then when you store it, I guess it was implicitly converted back to a numeric value? It's odd to me that you didn't receive an error message during any of this.
In any event, you're looking at two fixes:
For now, get rid of those single-quotes and treat the numeric value as a numeric value instead of a string value.
Don't build your queries by concatenating strings. The problem you're facing now is one of the lesser problems you'll encounter by doing this. Exposing yourself to SQL injection attacks is another, more significant problem. Use query parameters instead of string concatenation.

This is a textbook case. You need a transaction to encapsulate the two commands.
You also need to use a parameterized query and not a string concatenation.
decimal sumOfTransaction = 5m;
string creditAccount = "123456ABC";
string debitAccount = "ABC9876543";
using(TransactionScope scope = new TransactionScope())
using(SqlConnection cn = new SqlConnection(connectionString))
{
string upd1 = #"UPDATE Table1 SET currentMoney = currentMoney + #amount
WHERE accountNo=#account";
string upd2 = #"UPDATE Table1 SET currentMoney = currentMoney - #amount
WHERE accountNo=#account";
cn.Open();
using(SqlCommand cmd = new SqlCommand(upd1, cn);
{
cmd.Parameters.AddWithValue("#amount", sumOfTransaction);
cmd.Parameters.AddWithValue("#account", creditAccount);
cmd.ExecuteNonQuery();
cmd.CommandText = upd2;
cmd.Parameters["#account"].Value = debitAccount);
cmd.ExecuteNonQuery();
}
scope.Complete();
}
The use of a transaction is mandatory here, because you don't want, for ANY reason to credit some amout of money to one account and for whatever reason miss to debit the other account.
(In real cases you need a lot more than this. For example, this code lacks of any checks against the amount available in the debit account).
Of course your initial error is due to the fact that you are treating your amount as it was a string but this is plainly wrong. When dealing with money values you should not rely on implicit conversions of any kind.

compose sql string in this way is a very bad practice. You should use Sql Parameters instead.
Anyway, try this way:
string queryString4 = "UPDATE Table1 SET currentMoney =currentMoney + (" + money + ") WHERE accountNo='" + recipientNo + "';";
But i strongly advise you to use parameters.

Related

How to fix "System.Data.OleDb.OleDbException: 'Syntax error in UPDATE statement.'"?

I have been getting a syntax error in my UPDATE datagridview code which happens to work in another .cs file. My group has been looking at different solutions online but everything won't work.
My group has been looking at different solutions online but everything won't seem to work.
{
connection.Open();
OleDbCommand cmd = connection.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "Update Table1 set treatment = '" + treat.Text + "', remarks = '" + appRemarks.Text + "', cost = '" + treatCost.Text + "', Time = '" + textBox2.Text + "' where lastName = '" + Lastname.Text + "' ";
cmd.ExecuteNonQuery();
connection.Close();
MessageBox.Show("Updated Successfully!");
}
The expected output should be Updated Successfully! and it should reflect in the database file after clicking the update button. Sometimes the output is "Microsoft Engine database" which does not save the changes.
The error says "System.Data.OleDb.OleDbException: 'Syntax error in UPDATE statement.'" pointing to cmd.ExecuteNonQuery();
First, never use string concatenation to build a query. You're asking for a SQL Injection attack. The biggest thing I could see here is make sure that only columns that are string columns (varchar, char, text, etc..) have single-quoted values. Is cost a number? If so then it should be:
, cost=" + treatCost.Text + ",
If cost is a number, also make sure that there isn't a currency amount in the input field. If someone puts in 1,422.00 it's not a number and will fail since , is for decoration.
If someone puts in $1422.00 it's not a number as $ is for decoration.
Either of these would fail the query.
This would happen if someone types an apostrophe into the remarks field, which SQL server will interpret as the ending quote of the string. But much worse things can happen if the user knows a bit of sql and wants to cause trouble. For example, putting '-- in the remarks will result in
Update Table1 set treatment = 'blah', remarks = ''-- where lastName = 'foobar'
which will overwrite every row in the table, not only the one containing foobar.
Use query parameters so that user-provided values can't be interpreted as query keywords and structure.
Instead of remarks = '" + appRemarks.Text + "' you will have remarks = #Remarks as well as
cmd.Parameters.Add("#Remarks", SqlDbType.NText).Value = appRemarks.Text;
and all the other user inputs likewise.

C# SQL SELECT not working with WHERE = decimal variable

This is my code:
string query = "SELECT TEKN,KOMMENTAR FROM dbo.JOBBTEKN WHERE JOBBNR = " + jobId + ".00";
SqlDataReader reader = new SqlCommand(query, sqlConn).ExecuteReader();
This is my data:
I want to fetch multiple rows with the exact JOBBNR, but this returns nothing.
EDIT:
The query was working, it was just me being stupid and not searching in the right table. Sorry for wasting anyones time trying to help.
Include the jobId in single quotes. Modify your query to following:
"SELECT TEKN,KOMMENTAR FROM dbo.JOBBTEKN WHERE JOBBNR = '" + jobId + ".00'"
Observe the single quote around jobId.
Looking at the comments, I suspect the datatype of JOBBNR is float; NOT decimel. float datatype internally contains multiple precision, so when you try to match them in WHERE = clause, you may not get result due to mismatched precision.
There are multiple ways to handle this problem. Try something like following:
WHERE JOBBNR BETWEEN 1200.00 AND 1200.01
OR
"WHERE JOBBNR BETWEEN '" + jobId + ".00' AND '" + jobId + ".01'"

SQL query not working properly in C# while a lot of data is applied one by one

I have a problem while reading from SQL Server in C#. It is happening in SSIS, I have inserted a C# script in data flow.
I am using the code below:
using (SqlConnection connection = new SqlConnection(connectionString))
{
string vendorName = Row.VendorName.ToString().Substring(0,1).ToUpper() + Row.VendorName.ToString().Substring(1);
using (SqlCommand command = new SqlCommand("Select TOP 1 * from Logs where MessageId = '" + Row.id.ToString() + "'" +
"AND name = (Select Id from Names where vendor_name = '" + vendorName +
"order by CreatedDate desc", connection))
{
connection.Open();
string status = "";
using (SqlDataReader oReader = command.ExecuteReader())
{
while (oReader.Read())
{
status = oReader["Status"].ToString();
}
}
if (String.IsNullOrEmpty(status))
{
SaveDataToDB(Row.id, Row.VendorName, "Unknown");
}
}
}
In the Logs table, there are about 10000 rows, and the related datasource, where Row data belongs to, has around 9000 records. The problem is that, even though the query is working well, in the script it sometimes brings status value as null, because it cannot find the record in the SQL. I am getting the query and copy/pasting it to SQL, executing the query brings result there, but not in C# somehow. For example, I am running the C# two times in sequence, at the first time it says Status is null for the id: 354456, but when I run it at the second time it finds 354456 correctly but saying that status of 354499 is null.
Any idea for me to solve this issue? I really appreciate for any help.
According to me, this could be due to order of evaluation of user defined values embedded within the query. Could be the first dynamic value might be evaluated before the one in the inner query.
As I am not sure about the value to variable binding, however, I would recommend you to check following points;
a) externalise both your variable (vendor name and row id) outside and evaluate and ensure it has respective values
b) and then form your query statement with the evaluated values
May be you can debug and see the CommandText of command object just before call Execute.
your code is really inefficient, you should cache vendorname in a string and do all the substring operations on that.
for example:
string vendorName = Convert.ToString(Row.VendorName);
vendorName = vendorName.Substring(0,1).ToUpper() + vendorName.Substring(1);
instead of selecting all the columns, select the specific column for a speed up select Status from.
try to debug your code first, see which id you are getting and what is the result of your query.
its really hard to debug your code without any debug information.
change your code to this (Select Id from Names where vendor_name = '" + vendorName + "')" and put a blank space next to every " character e.g. " AND instead of "AND

Use of commercial #AT when dealing with data access in ASP.Net?

Two small issues, mostly concerning the #AT syntax when dealing with data in ASP.Net (C#). Most online tutorials show a lot of this following type of code but fail to mention (or I may have overlooked) the actual purpose of the ampersand although they do explain the general purpose of the code. In this example, just querying the database to get data pertaining to a certain month for a calender control.
protected DataSet GetCurrentMonthData(DateTime firstDate,
DateTime lastDate)
{
DataSet dsMonth = new DataSet();
ConnectionStringSettings cs;
cs = ConfigurationManager.ConnectionStrings["ConnectionString1"];
String connString = cs.ConnectionString;
SqlConnection dbConnection = new SqlConnection(connString);
String query;
query = "SELECT HolidayDate FROM Holidays " + _
" WHERE HolidayDate >= #firstDate AND HolidayDate < #lastDate";
SqlCommand dbCommand = new SqlCommand(query, dbConnection);
dbCommand.Parameters.Add(new SqlParameter("#firstDate",
firstDate));
dbCommand.Parameters.Add(new SqlParameter("#lastDate", lastDate));
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(dbCommand);
try
{
sqlDataAdapter.Fill(dsMonth);
}
catch {}
return dsMonth;
}
First issue: What do #firstDate and #lastDate mean or reference in the database string query? Is that referencing the parameters being passed in GetCurrentMonthData method or the actual column name in the database table ?
query = "SELECT HolidayDate FROM Holidays " + _
" WHERE HolidayDate >= #firstDate AND HolidayDate < #lastDate";
Second issue: What is the difference between #firstDate and firstDate? Am I correct in saying firstDate is the actual parameter variable itself?
dbCommand.Parameters.Add(new SqlParameter("#firstDate",
firstDate));
I agree with #har07. That is not a ampersand. An ampersand, as far as I know, looks like this -> &. To answer the question, the 'at' sign (#) is used to indicate variables in a parameterized query in c#.
In the code
dbCommand.Parameters.Add(new SqlParameter("#firstDate",firstDate));
you are assigning the value of the DateTime variable firstDate to the #firstDate variable in your query.
Here's an example that's a bit less confusing(I hope):
Let's say I have a string variable called myName and I want to pass that to my query select * from students where name = #name.
To pass the value of myName to #name in my query, I would do
dbCommand.Parameters.Add(new SqlParameter("#name",myName));
I hope that helps.
Your First Question :
According to the documentation, the name must start with an #:
The ParameterName is specified in the form #paramname.
More Information :
Is it necessary to add a # in front of an SqlParameter name?
Second Question :
First, that isn't ampersand but at sign or commercial at. It is used in this particular context to indicates an SQL parameter name.
And this part showing how you pass the actual value (contained in the firstDate C# variable) to the SQL parameter (#firstDate) :
dbCommand.Parameters.Add(new SqlParameter("#firstDate",
firstDate));
You can read your parameterized SQL query statement like string concatenation but with big advantages (the former save you from SQL injection, arbitrary data type to string conversion with correct formatting*, etc) :
query = "SELECT HolidayDate FROM Holidays " + _
" WHERE HolidayDate >= " + firstDate + " AND HolidayDate < " + lastDate;
*) See that in the string concatenation version above you need to convert firstDate and lastDate to string with correct format according to your RDBMS local settings to make it work.
The main use of #inputvalue in query statement is to avoid sql injection attacks.
If you use normal concatenation method in building query statement, Hackers can easily bypass the statements with sql injection.
Eg:
"Select * from user where username ='" + username.text + "' and password ='" + password.text + "'"
If you use the above statement to validate the user login, think what will happen if the user types a' = 'a') or 'sometext in username textbox and sometext in password box. It will returns more than one record on execution and enters into account area, if you checks with no of return records in user validation.
To avoid this, Microsoft introduced #parameter to build sql query statements. Whatever value you pass in the #parameter is considered as input parameter value and you can't inject sql statements in it.
Answer for your second question
dbCommand.Parameters.Add(new SqlParameter("#firstDate",
firstDate));
The above method is used to replace the #parameter(first argument in Add method) with parameter value(second argument in Add method). It uses # as the delimiter. it checks if there is a word with prefix '#' in query statement, it will be marked as a parameter and it is replaced by the actual value which is passed as the second argument in the Add method.

Compare date from database using parameters

string queryString = "SELECT SUM(skupaj_kalorij)as Skupaj_Kalorij "
+ "FROM (obroki_save LEFT JOIN users ON obroki_save.ID_uporabnika=users.ID)"
+ "WHERE (users.ID= " + a.ToString() + ") AND (obroki_save.datum= #datum)";
using (OleDbCommand cmd = new OleDbCommand(queryString,database))
{
DateTime datum = DateTime.Today;
cmd.Parameters.AddWithValue("#datum", datum);
}
loadDataGrid2(queryString);
I tried now with parameters. But i don't really know how to do it correctly. I tried like this, but the parameter datum doesn't get any value(according to c#).
please try this :
database = new OleDbConnection(connectionString);
database.Open();
date = DateTime.Now.ToShortDateString();
string queryString = "SELECT SUM(skupaj_kalorij)as Skupaj_Kalorij "
+ "FROM (obroki_save LEFT JOIN users ON obroki_save.ID_uporabnika=users.ID)"
+ "WHERE users.ID= " + a.ToString()+" AND obroki_save.datum= '" +DateTime.Today.ToShortDateString() + "'";
loadDataGrid2(queryString);
when you use with Date, you must write like this
select * from table where date = '#date'
not like
select * from table where date = #date
While it's usually useful to post the error, I'd hazard a guess and say that you're getting a conversion error with your date.
You should really look at parameterising your queries...
You should read this: http://www.aspnet101.com/2007/03/parameterized-queries-in-asp-net/
And if you can't be bothered reading that, then try changing your 'a' variable to '1; DROP TABLE obroki; --' (but only after you back up your database).
Perhaps you need to write your SQL string in the SQL dialect of the database you're using. In Jet/ACE SQL (what's used by Access), the delimiter for date values is #, so you'd need this:
obroki_save.datum= #" +DateTime.Today.ToShortDateString() + "#"
Of course, some data interface libraries translate these things for you, so that may not be the problem here.

Categories

Resources