Multiple "OR" variables in SqlCommand - asp.net

The database table has the following fields: UserName and FavColour. Basically, it stores the favourite colour of each user.
Instead of using concatenation, I use SqlCommand to store the information in my DataSet. It's easy when I've got 1 variable (like this):
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT * FROM Colour WHERE FavColour = #favcol";
cmd.Parameters.AddWithValue("#favcol", colourVar);
Now, I have a checkbox selection where I can choose the colour(s) for the WHERE clause. Say I've selected blue, pink, orange, and purple this time. How would I accomplish this using SqlCommand?
(Note: The number of colours selected could vary each time)

A straightforward and efficient way is to build your query.
SqlCommand cmd = new SqlCommand();
cmd.CommandText = String.Format(
"SELECT * FROM Colour WHERE FavColour IN ({0})"
, String.Join(",", MyColors.Select(c => String.Format("'{0}'", c.Replace("'", "''"))).ToArray())
);

If you want to pass multiple parameters of the same "type" to SQL Server, the "most-correct" way to do it is using table-valued parameters.
If you're not on a version of SQL Server that supports these, the next best way is to pass an XML document and use the XML functions in SQL Server to shred these back into a row-set.
The worst way you can do it is to pass a comma separated string and then have to split that back apart in SQL.
I can't decide where looping in C# and just adding as many parameters as necessary fits into the above. For a simple query such as the one shown, it may fit as the simplest option. I.e. the code would look something like:
SqlCommand cmd = new SqlCommand();
int i = 1;
var parms = new List<string>();
foreach(var colourVar = /* Obtain selected colours one at a time */)
{
var parmName = "#favcol" + i.ToString();
cmd.Parameters.AddWithValue(parmName, colourVar);
parms.Add(parmName);
}
cmd.CommandText = "SELECT * FROM Colour WHERE FavColour IN (" + string.Join(",",parms) + ")";
This wouldn't work if/when the literal query was replaced with a stored procedure, but for a small number of possible selections, it will work.

Related

Query SQL Server using session variable

I'm trying to query a SQL Server database table based on a user variable (using ASP.NET and C#). I want to be able to pull just the user's unique records from the Waste Application Information table where the Farm Owner name is equal to the variable name (which is a string).
Here's part of my code:
conn.Open();
WasteAppData = "SELECT * FROM [WASTE APPLICATION INFORMATION] WHERE [FARM OWNER] = (user variable) ";
SqlCommand com = new SqlCommand(WasteAppData, conn);
GridView1.DataSource = com.ExecuteReader();
GridView1.DataBind();
If I replace the "(user variable)" with the actual value in the table column it does work correctly. Like this: 'Joe Smith' I've tried referencing the variable which is pulled from another webform with no luck... I think my syntax is incorrect? Any help would be great!
You need to do it this way:
WasteAppData = "SELECT * FROM [WASTE APPLICATION INFORMATION] WHERE [FARM OWNER] = #FarmOwn";
using (SqlCommand cmdSQL = new SqlCommand(WasteAppData , conn)
{
cmdSQL.Parameters.Add("#FarmOwn", SqlDbType.NVarChar).Value = strFarmOwnwer;
cmdSQL.Connection.Open();
GridView1.DataSource = cmdSQL.ExecuteReader;
GridView1.DataBind();
}
In this case "strFarmOwner" would be replaced with your actual variable that holds the value you want.

select Query with AND Condition

I want to select user but i cant get it .
Here's my query
SqlCommand myCommand = new SqlCommand("Select * from Users where Email=" + UserEmailPass.Email + "And Password=" + UserEmailPass.Password, conn);
SqlDataReader Detailsreader = myCommand.ExecuteReader();
Is my query correct or not>? please help
If Email and Password are string fields then you need to encapsulate the values used for comparison in single quotes, but the correct way is to use a parameterized query
SqlCommand myCommand = new SqlCommand("Select * from Users " +
"where Email=#mail And Password=#pwd" conn);
myCommand.Parameters.AddWithValue("#mail",UserEmailPass.Email);
myCommand.Parameters.AddWithValue("#pwd",UserEmailPass.Password);
SqlDataReader Detailsreader = myCommand.ExecuteReader();
If you use a parameterized query you avoid the SQL Injection problem and you don't have to worry to encapsulate your string values with quotes, doubling them if your values contain themselves a quote, not to mention the appropriate decimal separator for numerics and the correct formatting of dates.
An often overlooked benefit of parameterized query is the now clear and perfectly understandable text of your query. As pointed out by Mr Tim Schmelter below, your query has a syntax error missing a space between AND and the previous value in the WHERE clause. This kind of errors are more difficult to do if you write a parameterized query.
Give me parameterized query or give me death
SqlCommand myCommand = new SqlCommand("Select * from Users where Email=#mail and Password#pass" , conn);
System.Data.SqlClient.SqlParameter par = new System.Data.SqlClient.SqlParameter("#mail", UserEmailPass.Email );
System.Data.SqlClient.SqlParameter par1 = new System.Data.SqlClient.SqlParameter("#pass", UserEmailPass.Password);
myCommand.Parameters.Add(par);
myCommand.Parameters.Add(par1);
SqlDataReader Detailsreader = myCommand.ExecuteReader();
DO NOT USE string concat!!!!

Securing data before update

I have a few text boxes that on my page that can add data to my database. What I'm looking for is how to actually make it more secure. The basic error checking of empty text boxes I know how to check. What I'm really searching for is bad data being saved or special characters like " ' " or " - ". Its a simple application only myself and maybe two other people will use it but still want to make sure learning and coding correctly. Any suggestions. This is my save button.
Here is my code:
try
{
OleDbConnection conn = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=H:\Databases\AddressBook.mdb");
conn.Open();
DataSet ds = new DataSet();
string cmd = "SELECT * FROM tblAddressBook";
OleDbDataAdapter da = new OleDbDataAdapter(cmd, conn);
da.Fill(ds, "Display");
DataRow newRow = ds.Tables["Display"].NewRow();
newRow[1] = txtFirstName.Text;
newRow[2] = txtLastName.Text;
newRow[3] = txtEmail.Text;
newRow[4] = txtPhone.Text;
ds.Tables["Display"].Rows.Add(newRow);
OleDbCommandBuilder cb = new OleDbCommandBuilder(da);
cb.DataAdapter.Update(ds.Tables["Display"]);
conn.Close();
GridView1.DataBind();
}
catch (Exception)
{
lblErrorSave.Text = "Your information did not save clear form and try again";
}
Your code as shown is secure, but does have problems.
What your question is about is SQL Injection. This arises where you use dynamic SQL, like so (air code):
string sql = "insert into tableA (cola, colb) values ("
+ "'" + txtBox1.Text + "',"
+ "'" + txtBox2.Text + "')";
...and then go and execute it. Depending on the contents of the text boxes you could have all sorts of things happening. Something like "');drop table tableA;--"
This does not happen when you use a DataSet as above, so that's OK
Hoewever, your code is very inefficient. The first thing you do is pull down the whole of the Address table. If this is any size it will be slow and add a lot of IO, memory, and computation to the procedure.
You are also not checking that the row to be entered is actually a new one, not a modification of an old one or a duplicate. This may or may not be important to your app, but usually is important (dup data can be a real pain). You can amend your read of the Address table to pull down e.g. a row with the same email address (or whatever is unique), and if it gets it then amend with new data as you do above.
However if the data is to be added, then you need to use parameters; Air Code again:
string sql = "insert into table (colA, colB) values (#colA, #colB)";
using (OleDbCommand com = new OleDbCommand(sql, conn))
{
com.Parameters.Add("#colA", txtBox1.Text);
com.Parameters.Add("#colB", txtBox2.Text);
com.ExecuteNonQuery();
}
(Note that different drivers have slightly different syntax on adding Parameters and I'm not sure that the OleDb command supports this syntax, but there will be something close.)
Using Parameters prevents SQL Injection, as the values of the parameters are transported not intermixed in the SQL string and so their content has no effect of the SQL eventually executed.

What is wrong with the following query?

I have a table containing name, surname and email. I want to retrieve them from the table and so i write:
if (LoginAs.SelectedValue == "Administrator")
{
string result;
string query = "Select * from AdminTable where ID='"+ idBox.Text +"'";
cmd1 = new SqlCommand(query, con);
result = Convert.ToString(cmd1.ExecuteScalar());
Response.Redirect("Admin.aspx");
//Admin user = new Admin(idBox.Text, "Active", mail, firstName, LastName, passwordBox.Text);
}
The problem is, it only returns the name field of the specified row even though i wrote "Select *". What is wrong here?
ExecuteScalar returns just the first column of the first row, and ignores the rest.
So you should use ExecuteReader method. An example from MSDN:
using (SqlConnection connection = new SqlConnection(
connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand(queryString, connection);
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(String.Format("{0}", reader[0]));
}
}
Note that the while (reader.Read()) checks whether your query returned (more) results and positions the cursor on the next record, that you can then read. This example prints the first column's value.
The using statement makes sure the connection is closed after use, whatever happens.
Also, don't build your query directly with input from the user (such as the value of a TextBox), use parameters instead to prevent SQL injection attacks.
You must try ExecuteReader() instead of using ExecuteScalar()
ExecuteScaler is used in situation where we have to read a single value.eg:
select count(*) from tablename.
while
ExecuteReader is used for any result set with multiple rows/columns
(e.g., SELECT * from TableName)
Sample code:
string myQuery="Select * from AdminTable where ID=#myid";
SqlCommand cmd=new SqlCommand(myQuery,conn);
cmd.Parameters.AddWithValue("#myid", value);
conn.Open();
SqlDataReader dreader;
dreader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (dreader.Read())
{
string Value1= dreader["COl1"].ToString();
string Value2= dreader["COl2"].ToString();
}
dreader.Close();
Always use parameterized Query
You may try cmd1.ExecuteReader() instead.

Executing query in c# asp.net

I've created a query to select the body of a message from the message database. I'm not sure how to execute it to get the body string back and store it. I've tried using ExecuteReader, ExecuteScalar, and ExecuteNonQuery. None of them work. ExecuteScalar was the closest to working but it only returned the body of the message of the first row no matter which row you were trying to view. Anyone know how to do this? It's gotta be a easy fix.
SqlCommand com = new SqlCommand("SELECT Body FROM Messages WHERE MessageID= MessageID", conn);
com.Connection = conn;
com.Connection.Open();
String body;
body = com.ExecuteScalar.ToString;
That's what I have now. Thanks in advance!
What is messageId in your query? You should be doing something like this
SqlCommand com = new SqlCommand("SELECT Body FROM Messages WHERE MessageID = #MessageId");
com.Parameters.AddWithValue("#MessageId", 1); //Replace 1 with messageid you want to get
string s = com.ExecuteScalar().ToString()
You can use SQLDataAdapter and Datatable for this :
SqlCommand com = new SqlCommand("SELECT MessageID,Body FROM Messages WHERE MessageID= MessageID", conn);
SqlDataAdapter dadapter=new SqlDataAdapter();
DataTable dt = new DataTable();
com.Connection = conn;
com.Connection.Open();
String body;
dadapter.SelectCommand=com;
dadapter.Fill(dt);
body = dr.Rows["Body"].toString();
you should try something like this.
SqlCommand com = new SqlCommand("SELECT Body FROM Messages WHERE MessageID= MessageID", conn);
com.Connection = conn;
com.Connection.Open();
String body;
SqlDataReader dr = com.ExecuteReader();
if(dr.HasRows){
while(dr.Read()){
body+=dr["Body"].ToString();
}
}
I hope this works for you.
Based on your reply to Nudier below, you're trying to pass in the messageID of the selected message by using WHERE MessageID = MessageID
The reason this won't work, and the reason you're always getting the first row returned is that SQL doesn't know that MessageID is a variable you're trying to pass in. As far as SQL knows, MessageID is a column name, so all you're asking SQL to do is select the column "Body" of the row where the column MessageID = the column MessageID, so where MessageID equals itself, which always equates to true. And since ExecuteScalar always returns the first cell of the first row, your query will always return all rows from the Messages table, and the executeScalar will grab the first cell.
Hopefully that made sense, if not, just copy your query and run it against your SQL database, you should see what I mean about it returning all rows as the where clause always equals true.
To fix it, you need to take into account what Anuraj said about adding a parameter.
To pass in a variable to a SQL string in code, you need to parameterise it, then add the relevant parameter, so your SQL should become:
SELECT Body FROM Messages WHERE MessageID=#MessageID
(Notice the addition of the # symbol before the parameter name?)
And directly below that line, you need to add the parameter in code using:
com.AddParameterWithValue("#MessageId", MessageId);
(I think that's right, I copied it from Anuraj, I normally do it slightly differently)
Again, to see this working, you can run it directly against the database with a parameter by using
DECLARE #messsageID AS INTEGER
SET #messageID = 1
SELECT Body FROM Messages WHERE MessageID=#messageID
Have a read of this for more details (or if I haven't managed to be entirely clear) http://www.csharp-station.com/Tutorial/AdoDotNet/lesson06

Resources