How can I add a variable to my SQL string and run it against the server successfully? I want to run this statement through my C#
protected void RunSQLQuery(string salesman, string connectionString)
{
SqlConnection cnn;
SqlCommand cmd;
StringBuilder sql = new StringBuilder();
SqlDataReader reader;
cnn = new SqlConnection(connectionString);
sql = new StringBuilder();
sql.Append("update database ");
sql.Append("set shippdate = GetDate() ");
sql.Append("where salesman = "' + salesman + "'");
sql.Append("and managerapproval is not null ");
cnn.Open();
cmd = new SqlCommand(sql.ToString(), cnn);
reader = cmd.ExecuteReader();
reader.Close();
cmd.Dispose();
cnn.Close
}
This presents multiple compile errors underlining my +salesman+ code. The errors are:
Only assignment, call, increment, decrement, and new object
expressions can be used as a statement
; expected
) expected
Too many characters in character literal Newline in constant
You are not adding the string object that salesman refers, you are adding salesman as a string literal.
Just add it as a parameter like;
var cmd = new SqlCommand("update database set shippdate = GetDate() where salesman = #salesman");
cmd.Parameters.Add("#salesman", salesman);
...
And use ExecuteNonQuery to execute your command, not SqlDataReader. This SqlDataReader is for return some data.
But more important, you should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
Also use using statement to dispose your connection and command automatically instead of calling Close or Dispose methods manually.
As a full example;
protected void RunSQLQuery(string salesman, string connectionString)
{
using(var cnn = new SqlConnection(connectionString))
using(var cmd = cnn.CreateCommand())
{
cmd.CommandText = #"update database set shippdate = GetDate()
where salesman = #salesman";
// I assume your column is nvarchar
cmd.Parameters.Add("#salesman", SqlDbType.NVarChar).Value = salesman;
cnn.Open();
cmd.ExecuteNonQuery();
}
}
For myself, I always prefer to use SqlParameterCollection.Add(string, SqlDbType, Int32) overload to specify my parameter type and it's size but since you never mentioned your salesman column type, I couldn't post this in my example.
As you can also see from the syntax highlighting, the compile errors are caused because you did not escape the quotes properly in sql.Append("where salesman = "' + salesman + "'");.
As a side note, you should never insert strings into sql queries without first validating them, or you are open to sql injection, e.g. if i pass "''; drop table database;" as salesman parameter. It is better to use SqlParameter.
I would suggest using the AddWithValue method from your sql command combined with the UPPER function to make it case insensitive:
SqlCommand cmd = cnn.CreateCommand();
cmd.CommandText = "UPDATE database SET shippdate = GetDate() WHERE UPPER(salesman) = UPPER(#salesMan)";
cmd.Parameters.AddWithValue("#salesMan", salesman);
if (cnn.State.Equals(ConnectionState.Closed))
{
cnn.Open();
}
cmd.ExecuteNonQuery();
cnn.Close();
As mentioned in above answers, yes, writing queries in this way is not a good way to do it. But still if you want to do it that way only, you will have to change:
sql.Append("where salesman = "' + salesman + "'");
to
sql.Append("where salesman = '" + salesman + "'");
Related
I have the following code which seems pretty standard on face value, however in query is another SQL statement hence why the 'AS QUERY' is at the end of the SQL string. I wanted to know if there was a sophisticated approach to parameterising the following SQL command instead of concatenating the entire query together.
The only solution I could think of would be to instead of having a query as a string, have it as an SQLCommand type object and initiate 2 commands. 1 to could and the other to display the preview of the data.
public static CommandStatus<int> GetQueryRecordCount(SqlConnection connection, String query)
{
String sql = "SELECT COUNT(1) FROM (" + query + ") AS QUERY";
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = sql;
cmd.Connection = connection;
cmd.CommandTimeout = GetTimeout();
try
{
SqlDataReader dataReader = cmd.ExecuteReader();
dataReader.Read();
String count = dataReader[0].ToString();
dataReader.Close();
return new CommandStatus<int>(Int32.Parse(count));
}
catch (Exception e)
{
return new CommandStatus<int>("Failed to GetQueryRecordCount[" + sql + "]:" + e.Message, e);
}
}
String SQL will end up being something like this
"SELECT COUNT(1) FROM (SELECT TOP 20 [RecordID],[Name],[SonsName],[DadsName],[MothersName],[DaughtersName] FROM [dbo].[sample] ) AS QUERY"
This function is literally SQL injection by design.
Whitelisting the SQL queries this function will accept is the only way to make it safe.
That is, the caller won't be able to inject any SQL query, they'll only be able to pick from a fixed list of pre-vetted queries. The list could even be defined as an array of static strings in the function you show.
But then they don't need to pass the whole query as a string, they only need to pass an ordinal integer to identify which query in the whitelist to run.
C#, Razor
my code is:
#using (SqlConnection Praktikum2 = new SqlConnection("Data Source=Mark\\SQLEXPRESS;Initial Catalog=Connection;Integrated Security=True"))
{
using(connection)
{
SqlCommand command = new SqlCommand("SELECT KategoryID FROM Kategory WHERE Name = " + Request.Params["kategory"]);
connection.Open();
SqlDataReader reader = command.ExecuteReader(); //ERROR!!!
while (reader.Read())
{
string ID = reader["KategorieID"].ToString() ;
Console.WriteLine("ID = {0}", ID);
}
reader.Close();
};
}
i get an error that there's a wrong syntax near "=".
how can i solve this?
The problem is caused by the missing quotes around the value passed for your search. You could add a set of single quote before and after the value obtained by the Request but that would be a bigger error and the source of a problem called Sql Injection.
The only way to handle this is to use a parameter query
SqlCommand command = new SqlCommand(#"SELECT KategoryID FROM Kategory
WHERE Name = #name", connection);
command.Parameters.Add("#name", SqlDbType.NVarChar).Value = Request.Params["kategory"];
Also, as noted in another answer, your code seems to not have associated the connection to the command, I think that it is just a typo here because the error message in that case would be 'need an open connection'
You forgot to assign the connection to the command. So when you call ExecuteReader(), it does not know on which connection it should be executed.
You can assign the connection like this:
SqlCommand command = new SqlCommand(
"SELECT KategoryID FROM Kategory WHERE Name = " + Request.Params["kategory"],
connection); // provide connection as second parameter!
or use connection.CreateCommand() to create your command.
Second, you forgot the quotation marks around your string:
"SELECT KategoryID FROM Kategory WHERE Name = '" + Request.Params["kategory"] + "'"
but inserting user data directly into your query opens your code to SQL Injection. Please use parameterized queries instead.
If your kategory column is not of integer data type then you need to surround your value with (') i.e single quote characters
Then your query will be like
SqlCommand command = new SqlCommand("SELECT KategoryID FROM Kategory WHERE Name ='" + Request.Params["kategory"] + "'");
The exception is caused by how you are creating your sql statement. The fix should not be correcting the syntax but using parameters instead. This will prevent sql injection attacks.
Also
You really should not be writting sql in your views, do it in your controller method instead and return the result in the Model to be used in your view. Better yet, abstract it to a different layer and call that layer from your controller. This has to do with SoS (Separation of Concerns), your code will very difficult to maintain if you just write everything into your views.
Wrap your connections, commands, and readers in using blocks.
Modified Code
#{
using(SqlConnection Praktikum2 = new SqlConnection("Data Source=Mark\\SQLEXPRESS;Initial Catalog=Connection;Integrated Security=True"))
using(SqlCommand command = new SqlCommand("SELECT KategoryID FROM Kategory WHERE Name = #name", Praktikum2))
{
command.Parameters.Add(new SqlParameter("#name", SqlDbType.VarChar){ Value = Request.Params["kategory"]});
connection.Open();
using(SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
string ID = reader["KategorieID"].ToString() ;
Console.WriteLine("ID = {0}", ID);
}
}
}
}
I'm trying to make an ATM Simulator. When I want to add some money in my account which is registered in SQL Server, I don't know how to add a value over the old value.
My SQL Table is like this:
Name | Surname | Pin | Money
When i want to add Money from textBox in the Money column I don't know how.
Code:
con.Open();
string connString = "";
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "select * from Useri where Pin='" + textBox1_Pin.Text + "' ";
var reader = cmd.ExecuteReader();
double balanciFillestar = Convert.ToDouble(reader[3]);
double balanciRi = balanciFillestar + double.Parse(textBox_shuma.Text);
cmd.CommandText = "update Useri set Shuma =" + balanciRi + "";
cmd.ExecuteNonQuery();
con.Close();
The most immediate need would be to filter the update statement, so instead of this:
cmd.CommandText = "update Useri set Shuma =" + balanciRi + "";
you really need this:
cmd.CommandText = "UPDATE Useri SET Shuma = #Shuma WHERE Pin = #Pin";
But, before you can do that we really need to refactor it all.
var selectSql = "SELECT Shuma FROM Useri WHERE Pin = #Pin";
var updateSql = "UPDATE Useri SET Shuma = #Shuma WHERE Pin = #Pin";
using (SqlConnection c = new SqlConnection(cString))
{
c.Open();
double balanciFillestar;
using (SqlCommand cmd = new SqlCommand(selectSql, c))
{
cmd.Parameters.AddWithValue("#Pin", textBox1_Pin.Text);
balanciFillestar = Convert.ToDouble(cmd.ExecuteScalar());
}
double balanciRi = balanciFillestar + double.Parse(textBox_shuma.Text);
using (SqlCommand cmd = new SqlCommand(updateSql, c))
{
cmd.Parameters.AddWithValue("#Shuma", balanciRi);
cmd.Parameters.AddWithValue("#Pin", textBox1_Pin.Text);
cmd.ExecuteNonQuery();
}
}
There are a number of things I'm doing here that you'll want to learn from:
The SQL statements are parameterized.
The SqlConnection is not shared.
The ADO.NET objects are wrapped in a using statement.
A SqlDataReader isn't used to get a single value from a single row.
All of these things, with the exception of #4, are equally important.
Point #1 ensures that you're protecting yourself from SQL Injection attacks.
Point #2 is quite simply the only viable way to use the class. It's meant to be constructed, opened, used, and disposed.
Point #3 ensures that the Dispose method is called on all of the objects. This is extremely important with these classes because they implement IDisposable. They do because they handle unmanaged resources (i.e. a connection to a SQL server).
Point #4 is really just an optimization. Data readers are meant for reading very large data sets, one row at a time, to gain performance and resource management. Likewise the data reader is actually left open until it is closed or disposed. Generally speaking there are almost always better API's to use than a data reader unless using it for their express purpose.
Your code is vulnerable against SQL injection. Please consider this and use parameterized query.
string ps= "update Useri set Shuma = Shuma + #shuma WHERE Pin= #pin";
SqlCommand cmd = new SqlCommand(ps, c);
cmd.Parameters.AddWithValue("#shuma", textBox_shuma.Text);
cmd.Parameters.AddWithValue("#pin", textBox1_Pin.Text);
I'm not sure why this is happening. I've seen the same issue online with little help out there to correct it.
When i run my query inside Access i get different values ranging from 0 - 10 but for some reason, it won't return that same value inside my code.
static int OrdersPerHour(string User)
{
int? OrdersPerHour = 0;
OleDbConnection conn = new OleDbConnection(strAccessConn);
DateTime curTime = DateTime.Now;
try
{
string query = "SELECT COUNT(ControlNumber) FROM Log WHERE DateChanged > #" + curTime.AddHours(-1) + "# AND User = '" + User + "' AND Log.EndStatus in ('Needs Review', 'Check Search', 'Vision Delivery', 'CA Review', '1TSI To Be Delivered');";
OleDbCommand dbcommand = new OleDbCommand(query, conn);
dbcommand.Connection.Open();
dbcommand.CommandType = CommandType.Text;
dbcommand.CommandText = query;
OrdersPerHour = (int?)dbcommand.ExecuteScalar();
}
catch (OleDbException ex)
{
}
finally
{
conn.Close();
}
return OrdersPerHour.Value;
}
Do not use string concatenation and the Access syntax to build your sql commands.
Use a simple parameterized query like this
string query = "SELECT COUNT(ControlNumber) FROM Log " +
"WHERE DateChanged > ? AND [User] = ? AND " +
"Log.EndStatus in ('Needs Review', 'Check Search', 'Vision Delivery'," +
"'CA Review', '1TSI To Be Delivered');";
OleDbCommand dbcommand = new OleDbCommand(query, conn);
dbcommand.Parameters.AddWithValue("#p1", curTime.AddHours(-1));
dbcommand.Parameters.AddWithValue("#p2", User);
dbcommand.Connection.Open();
dbcommand.CommandType = CommandType.Text;
OrdersPerHour = (int)dbcommand.ExecuteScalar();
In this way the burden to correctly interpret your value is passed to the Framework code that could format dates, decimals and strings according to your database requirements. By the way this will also prevent Sql Injection
Also, the word USER is a reserved keyword in Access SQL and thus you need to encapsulate it with square brackets
First and most important: Use Parametrized Queries!
Regarding your problem, I suggest you to debug the code:
Get the Commandtext of your "OleDbCommand dbcommand" and manually query to see if you get the same result.
Also, you should put your code within the try catch block, else it does not make sense at all.
I need to retrieve a value from a field in database. I have the used following code. but the value checkOrderId (which I need) shows the SQL string instead of the value from database. I don't know why it is doing so. Could somebody help me please?
string connectionString = "Data Source = xxyyzz;Initial Catalog = xyz; Integrated Security = True";
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
string tableName = "[GIS].[SecondaryTraffic].[PotentialBackHauls]";
string checkOrderId = "Select TOP 1 OrderID From" + tableName + "ORDER BY InsertDate DESC";
SqlCommand cmd = new SqlCommand(checkOrderId, connection);
//cmd.ExecuteNonQuery();
OpenPop.Pop3.Pop3Client popConn = new OpenPop.Pop3.Pop3Client();
if (orderIdentity == checkOrderId)
{
popConn.DeleteMessage(messageNumber);
}
connection.Close();
I am new and dont have reputation to answer my question immediately. With everybody's help, i got this one solved...Great help, thanx everybody...following is my code.
string connectionString = "Data Source = EAEDEV;Initial Catalog = GIS; Integrated Security = True";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string tableName = "[GIS].[SecondaryTraffic].[PotentialBackHauls]";
string checkOrderId = "Select TOP 1 OrderID From " + tableName + " ORDER BY InsertDate DESC";
SqlCommand cmd = new SqlCommand(checkOrderId, connection);
string valueReturned = (string)cmd.ExecuteScalar();
OpenPop.Pop3.Pop3Client popConn = new OpenPop.Pop3.Pop3Client();
if (orderIdentity == valueReturned)
{
popConn.DeleteMessage(messageNumber);
}
connection.Close();
}
You need to execute the query and check the results, here you are just comparing a string with the query SQL.
Please see here
http://www.csharp-station.com/Tutorial/AdoDotNet/lesson03
for a tutorial.
Your expectation of the result being set into checkOrderId is incorrect. In this instance checkOrderId is just the query to execute and not the actual result.
You need to read the value back from executing the command:
using (var connection = new SqlConnection(connectionString))
using (var comm = new SqlCommand("Select TOP 1 OrderID From [GIS].[SecondaryTraffic].[PotentialBackHauls] ORDER BY InsertDate DESC", connection))
{
connection.Open();
object result = comm.ExecuteScalar(); // This is the key bit you were missing.
if (result != null)
{
// You can cast result to something useful
int orderId = (int)result;
}
} // Both comm and connection will have Dispose called on them here, no need to Close manually.
ExecuteScalar returns the value in the first cell (ie, column 1 row 1) as an object that you can cast to a better type (depending on what type it was in the result-set schema).
If you need to read multiple values, you need to look at ExecuteReader.
There are also other ways of doing this using output parameters, but that would pollute the point of the answer.
You can add space to your query
"Select TOP 1 OrderID From " + tableName + " ORDER BY InsertDate DESC";
Nota : I suggest you to use AddWithValue method with your parameter
string checkOrderId = "Select TOP 1 OrderID From #tableName ORDER BY InsertDate DESC";
SqlCommand cmd = new SqlCommand(checkOrderId, connection);
cmd.Parameters.AddWithValue("#tableName", tableName );
Link : http://msdn.microsoft.com/fr-fr/library/system.data.sqlclient.sqlparametercollection.addwithvalue.aspx
You don't actually run your command anywhere. Instead of the commented-out cmd.ExecuteNonQuery, you should look into the ExecuteScalar method, which allows you to read back a single result value from a query - which is what your query returns.
Add
int i = (Int32) cmd.ExecuteScalar();
right after
SqlCommand cmd = new SqlCommand(checkOrderId, connection);
then the variable i will contain the order id
No, this is not correct. You are comparing the variable orderId to your query string. I doubt that's what you want to do. I imagine you'd be better off calling cmd.ExecuteScalar() to retrieve the actual OrderID value. As noted by other answers, your query string is missing a space. But most importantly, it is bad practice to construct SQL queries in code. Although I can't see a security issue with this code, if you continue to use this method you will probably write code that is vulnerable to SQL injection. I recommend you learn to either use parameters or LINQ to build your queries.