I want to execute this command
select * from table1 where id='"+comboBox1.Text+"'and name='"+comboBox2.Text+"'
but I don't want them to be considered if they were empty, for example if combobox1.Text is empty, I want the command to be like
select * from table1 where name='"+comboBox2.Text+"'
You can have a check with the text boxes like
if (comboBox1.Text.Trim().Length == 0) {
// your query
}
else{
// other query
}
But you should be using parameterised queries. Building up your queries like that leaves you open to SQL injection.
So your SQL String should be
select * from table1 where id=#id and name=#name
And you add the parameters to the command object before executing the query.
You can build up your query as you go, and still protect yourself from SQL injection:
(I'm writing this from memory, it should compile...)
using (var conn = new SqlConnection("..."))
{
var sb = new StringBuilder("SELECT * FROM table1 WHERE");
using (var cmd = new SqlCommand { Connection = conn })
{
if (!String.IsNullOrEmpty(comboBox1.Text))
{
sb.Append(" id = #ID");
cmd.Parameters.AddWithValue("#ID", int.Parse(comboBox1.Text));
}
if (!String.IsNullOrEmpty(comboBox2.Text))
{
sb.Append(" name = #NAME");
cmd.Parameters.AddWithValue("#NAME", comboBox2.Text);
}
var query = sb.ToString();
cmd.CommandText = query.EndsWith("WHERE") ? query.Remove(query.Length - 5) : query;
conn.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// do whatever you need to do with your data
}
}
}
}
Something to keep in mind...
This could get out of hand if you have a dozen if blocks instead of just two, and then start nesting more if blocks inside of those. Maintenance will become a nightmare.
It may just be easier, if you only have a few conditions, to just create a few separate queries and determine which one is called instead of building a query dynamically like this.
i found the solution i want
MySqlDataAdapter cmd = new MySqlDataAdapter("select * from table1 where (ID=#id or #id2) and (name=#name or #name2) ", co);
if (comboBox1.Text == "")
{
cmd.SelectCommand.Parameters.AddWithValue("#id", "1");
cmd.SelectCommand.Parameters.AddWithValue("#id2", "1");
}
else
{
cmd.SelectCommand.Parameters.AddWithValue("#id", comboBox1.Text);
cmd.SelectCommand.Parameters.AddWithValue("#id2", "0");
}
if (comboBox2.Text == "")
{
cmd.SelectCommand.Parameters.AddWithValue("#name", "1");
cmd.SelectCommand.Parameters.AddWithValue("#name2", "1");
}
else
{
cmd.SelectCommand.Parameters.AddWithValue("#name", comboBox1.Text);
cmd.SelectCommand.Parameters.AddWithValue("#name2", "0");
}
//thanks everyone for the help , i used all what u gave me to create this solution
Related
I'm trying to select values to a MySQL table.
I use the AddWithValue method, but it doesn't substitute what I have in the command string.
Here is some sample code that fails and the return is empty.
private DataSet RetrieveProducts()
{
DataTable dt1 = new DataTable();
DataTable dtProducts = new DataTable();
DataSet dsProducts = new DataSet();
var paramValuenamens = string.Join(", ", Masterpage.Container.TheObjectPropertyNameNs);
var strEmail = Masterpage.Container.TheObjectPropertyNameEmail.ToString();
string sql = #String.Format(" SELECT * FROM ");
sql += String.Format(" doTable ");
sql += String.Format(" WHERE 1 ");
if (Masterpage.Container.theObjectPropertyAut == 1)
{
sql += String.Format(" AND doTableEmail = ? ");
}
sql += String.Format(" AND doTableNameNs IN ({0}) ", paramValuenamens.ToString());
using (MySqlConnection myConnectionString =
new MySqlConnection(ConfigurationManager.ConnectionStrings["cn"].ConnectionString))
{
using (MySqlCommand cmd =
new MySqlCommand(sql, myConnectionString))
{
cmd.Parameters.AddWithValue("param1", strEmail.ToString());
foreach (var param in paramValuenamens)
{
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("param2", param.ToString());
}
MySqlDataAdapter adapter =
new MySqlDataAdapter(cmd);
adapter.Fill(dsProducts);
if (dsProducts.Tables.Count > 0)
{
dt1 = dsProducts.Tables[0];
}
dtProducts = dt1;
}
}
return dsProducts;
}
But if change my code from
if (Masterpage.Container.theObjectPropertyAut == 1)
{
sql += String.Format(" AND doTableEmail = ? ");
}
To
if (Masterpage.Container.theObjectPropertyAut == 1)
{
sql += String.Format(" AND doTableEmail = '" + strEmail.ToString() + "' ");
}
The return is correct...
I have tried this suggestion without success
How to do resolve this?
Can you help me, please?
Thank you in advance for any help
You are trying to use parameters without setting the proper placeholder in the query text.
So change the condition to....
if (Masterpage.Container.theObjectPropertyAut == 1)
{
sql += " AND doTableEmail = #email ");
}
....
Now add the parameter using the same name used for the placeholder
cmd.Parameters.AddWithValue("#email", strEmail);
Then you have a useless loop that clear the parameter collection at each loop.
You don't need it because you have already added the values directly through the string format above.
// foreach (var param in paramValuenamens)
// {
// cmd.Parameters.Clear();
// cmd.Parameters.AddWithValue("param2", param.ToString());
// }
Now this should work, but of course, this is not a complete parameterized query because the IN clause for the doTableNameNs still uses a string concatenation (Format is still a concatenation and doesn't keep you safe from sql injection). This is acceptable only if you are absolutely sure that the value used don't come from user input or other media that you cannot control. Otherwise you need to create a collection of parameters and strings placeholders to insert in the IN statement for doTableNameNs
I am using SQL Server 2012 & VS 2013. I have table schema like this
[dbo].[Accounts] ([AccntName], [AccntCrVal], [AccntDrVal])
I want to build a dynamic sql query depending on condition. User will select the AccoutnName and enter a Balance then choose balance type Credit or Debit. Now I want if user choose Credit values goes to credit column and vice versa. User will only select AccountName which already entered in the accounts table.
Currently I am doing this like this
using (SqlConnection conn = new SqlConnection(conStr))
{
insrtcmd = new SqlCommand();
insrtcmd.Connection = conn;
if (comBoxBalType.Text == "Cr")
{
insrtcmd.CommandText = #"INSERT INTO Accoutns(AccntCrVal) VALUES (#bal) Where(AccntName=#acntName)";
insrtcmd.Connection = conn;
insrtcmd.Parameters.AddWithValue("#acntName", acntName);
insrtcmd.Parameters.AddWithValue("#bal", bal);
conn.Open();
insrtcmd.ExecuteNonQuery();
}
else if (comBoxBalType.Text == "Dr")
{
insrtcmd.CommandText = #"INSERT INTO Accoutns(AccntDrVal) VALUES (#AccntDrVal) Where (AccntName=#prmSlctAcntName)";
insrtcmd.Connection = conn;
insrtcmd.Parameters.AddWithValue("#prmSlctAcntName", comBoxSlctAcnt.Text);
insrtcmd.Parameters.AddWithValue("#AccntDrVal", textBoxBal);
conn.Open();
insrtcmd.ExecuteNonQuery();
}
else
{
MessageBox.Show("Please Enter Values and Select the Balance Type [ Dr | Cr ] ", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
But I don't want to do like this. Thanks
As you already the data in the table, you need to Update the record. With your current setup, you can do something like this
using (SqlConnection conn = new SqlConnection(conStr))
{
var accountName = comBoxSlctAcnt.Text;
var balance = textBoxBal.Text;
var balanceType = comBoxBalType.Text;
if (balanceType == "Cr" || balanceType == "Dr")
{
insrtcmd = new SqlCommand();
insrtcmd.CommandText = string.Format(
#"UPDATE Accoutns SET {0} = #bal Where AccntName = #acntName",
balanceType == "Cr" ? "AccntCrVal" : "AccntDrVal");
insrtcmd.Connection = conn;
insrtcmd.Parameters.AddWithValue("#acntName", accountName);
insrtcmd.Parameters.AddWithValue("#bal", balance);
conn.Open();
insrtcmd.ExecuteNonQuery();
}
else
{
MessageBox.Show("Please Enter Values and Select the Balance Type [ Dr | Cr ] ", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
But, you should rather use a CheckBox or DropDown for selecting the transaction type, and also validate all the values before using them. Catch the exceptions, if any. Alternatively you can write a small stored proc and move the conditional logic from C# to SQL.
Looking at the example given here:
https://stackoverflow.com/a/452934
I understand that I will need to iterate through a loop and append value clauses, but what I am missing is how to amend the query to return all the ID's for the newly created records and retrieve them in C#?
For Example my current code can be seen below, I would like to change it to insert multiple rows in one query and retrieve the newly created Id's as a List of integers ideally.
in_new_id = -1;
String query = "INSERT INTO " + DB_Base.DBTable_Customer_Order_Table + "(" + DB_Base.DBTable_Customer_Order_Table_Customer_ID + "," + DB_Base.DBTable_Customer_Order_Table_ProductId+")";
query += " OUTPUT INSERTED." + DB_Base.DBTable_Customer_Order_Table_ID;
query += " VALUES ( #customerId, #productId);";
using (SqlConnection conn = new SqlConnection(GeneralConfig.DB_STR()))
{
SqlCommand sql_command = new SqlCommand(query, conn);
sql_command.Parameters.AddWithValue("#customerId", data_obj.customerId);
sql_command.Parameters.AddWithValue("#productId", data_obj.productId);
if (!String.IsNullOrEmpty(query) && sql_command != null && conn != null)
{
sql_command.Connection.Open();
if (sql_command.Connection.State == System.Data.ConnectionState.Open)
{
object out_new_id = sql_command.ExecuteScalar();
if (out_new_id != null)
{
in_new_id = (int)out_new_id;
}
sql_command.Connection.Close();
return ENUM_DB_Status.DB_SUCCESS;
}
else
{
in_new_id = -1;
return ENUM_DB_Status.DB_CONNECTION_COULD_NOT_OPEN;
}
}
}
return ENUM_DB_Status.DB_FAIL;
Use this:
List<int> ids = new List<int>();
using (SqlCommand command = new SqlCommand(#"declare #T TABLE(Id int)
INSERT INTO YourTableName(YourTableColumnNames)
OUTPUT Inserted.Id into #T VALUES
(YourValues1),
(YourValues2),
(YourValues3),
(etc...) select Id from #T ", con))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
int id = int.Parse(reader[0].ToString());
ids.Add(id);
}
}
}
Warning!!! This will work only if you're using SQLServer 2008 R2 or higher.
Edit: As Damien said in the comments : "There is no guarantee that the order in which the changes are applied to the table and the order in which the rows are inserted into the output table or table variable will correspond."
I am trying to store each row of a access database, based on column Veh_ID. The found data may or may not be based on multiple rows. The code I am currently using can copy single row but if there are multiple results I can only get the first result. Can anyone please help me on this? I am noob when it comes to database. I tried to search Google but no one seems to be needing what I need. Here's the code I'm using:
string cmd1 = "SELECT * FROM Veh_checkup WHERE Veh_ID = " + veh_idd + "";
OleDbCommand cmd = new OleDbCommand(cmd1, con);
OleDbDataReader read = cmd.ExecuteReader();
read.Read();
veh_id=null;
int i=0;
foreach (var a in read)
{
try
{
veh_id = veh_id + " " + read[i].ToString();
}
catch { }
i++;
}
There are a few things I would point out, some specific to your question, some not:
USE PARAMETERISED QUERIES
Use OleDbDataReader.Read() to move to the next record.
Use a StringBuilder to concatenate strings in a loop, using string = string + "something" will create a new string on the heap with each iteration
Use using blocks on Disposable objects
catch { } is not good practice. You will never know an error occurred. At the very least you should log the error somewhere so you know you need to fix something.
OleDbDataReader[i] will get the data from column i for the current record being read, not the data from row i
Don't use SELECT * in production code, especially if you are only using 1 column. It is unnecessary data retrieval from the database and also unnecessary network traffic.
USE PARAMETERISED QUERIES
Okay, I know I included using parameterised queries twice, but that is how strongly I feel about it!
With the above changes made, your full code will become something like:
static string GetStringData(string vehID)
{
StringBuilder builder = new StringBuilder();
string cmd1 = "SELECT Column1 FROM Veh_checkup WHERE Veh_ID = #VehID";
using (OleDbConnection con = new OleDbConnection("YourConnectionString"))
using (OleDbCommand cmd = new OleDbCommand(cmd1, con))
{
con.Open();
cmd.Parameters.AddWithValue("#VehID", vehID);
using (OleDbDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
builder.Append(" " + reader.GetString(0));
}
}
}
return builder.ToString();
}
You are using the datareader in a wrong way. Instead of calling it once like you do, you have to call the datareader in a while loop like this:
while(theDataReader.Read())
{
// do your stuff in a loop now
}
So using this approach in your code would look something like this:
string cmd1 = "SELECT * FROM Veh_checkup WHERE Veh_ID = " + veh_idd + "";
OleDbCommand cmd = new OleDbCommand(cmd1, con);
OleDbDataReader read = cmd.ExecuteReader();
veh_id=null;
con.Open();
while(read.Read()) //your reader
{
try
{
veh_id = veh_id + " " + read[i].ToString();
}
catch { }
}
Environment:
C#
Visual Studio 2012
.NET Framework 3.5
Hi
Could I parameterize where clause in SQL Server?
In my scenario, once a WHERE clause String is input, application will concatenate it to other part of query and execute in SQL Server then return the result.
For example,
User inputs "[CookingTime] < 30 and [Cost] < 20"
Application creates query "select [RecipeID] from [Recipes] where [CookingTime] < 30 and [Cost] < 20" and executes in SQL Server.
Application returns result to user.
For security reason, I would like to make whole WHERE CLAUSE as parameter.
But I have no idea how to achieve.
Thanks in advance.
This is how it can be done
string commandText = "UPDATE Sales.Store SET Demographics = #demographics "
+ "WHERE CustomerID = #ID;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(commandText, connection);
command.Parameters.Add("#ID", SqlDbType.Int);
command.Parameters["#ID"].Value = customerID;
// Use AddWithValue to assign Demographics.
// SQL Server will implicitly convert strings into XML.
command.Parameters.AddWithValue("#demographics", demoXml);
try
{
connection.Open();
Int32 rowsAffected = command.ExecuteNonQuery();
Console.WriteLine("RowsAffected: {0}", rowsAffected);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
The whole WHERE clause as parameter will be a victim of sql injection in any way. To prevent this you'd better to:
Setup proper permissions. So even in case of sql injected user can't access anything not granted. In this case sample of #Dhaval is better, because dymanic sql generation incapsulated in stored procedure requires less permissions to execute.
Check the statement for sql injection. The simplest way is to check for semicolons in order to avoid another statements in the batch. More complex and more precise way is to use t-sql DOM parser. For example:
using Microsoft.SqlServer.TransactSql.ScriptDom;
TSql110Parser parser = new TSql110Parser(true);
IList<ParseError> errors = null;
var condition = "a > 100; delete from [Recipes]";
var script = parser.Parse(new StringReader("select [RecipeID] from [Recipes] where " + condition), out errors) as TSqlScript;
if (errors.Count > 0)
{
throw new Exception(errors[0].Message);
}
foreach (var batch in script.Batches)
{
if (batch.Statements.Count == 1)
{
var select = batch.Statements[0] as SelectStatement;
if (select != null)
{
QuerySpecification query = select.QueryExpression as QuerySpecification;
if (query.WhereClause is BooleanBinaryExpression)
{
...
}
}
else
{
throw new Exception("Select statement only allowed");
}
}
else
{
throw new Exception("More than one statement detected");
}
}
You can create a dynamic query in sql server and pass the parameter from C#
Something like this
Create Procedure usp_Test
#WhereCond Varchar(max)
AS
Bgein
Set NoCount ON
Declare #SQLQuery AS Varchar(max)
Set #SQLQuery = 'Select * From tblEmployees where ' + #WhereCond
Execute sp_Executesql #SQLQuery
End
C# Code to execute the procedure
DataSet ds = new DataSet();
using(SqlConnection conn = new SqlConnection("ConnectionString"))
{
SqlCommand sqlComm = new SqlCommand("usp_Test", conn);
sqlComm.Parameters.AddWithValue("#WhereCond", WhereCond);
sqlComm.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = sqlComm;
da.Fill(ds);
}
I guess the original question wanted to find out how to make it dynamically from user's input and then use proper sql parameter to do the query.
For the usage of sql parameter, normally what I do is to use a generic helper method, a quick example (not tested):
public static class SqlHelpers
{
public static IEnumerable<T> ExecuteAdhocQuery<T>(SqlConnection con, string sql, CommandType cmdType, Func<SqlDataReader, T> converter, params SqlParameter[] args)
{
try
{
using (SqlCommand cmd = new SqlCommand(sql, con) { CommandType = cmdType })
{
cmd.Parameters.AddRange(args);
if (con.State != ConnectionState.Open) { con.Open(); }
var ret = new List<T>();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
ret.Add(converter.Invoke(rdr));
}
}
return ret;
}
}
catch (Exception e)
{
// log error?
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
throw e; // handle exception...
}
}
public void Test()
{
using (SqlConnection con = new SqlConnection("connection string here"))
{
var data = ExecuteAdhocQuery(con,
"SELECT ID, Name FROM tblMyTable WHERE ID = #Id and Status = #Status;",
CommandType.Text, (x) => new { Id = x.GetInt32(0), Name = x.GetString(1) },
new SqlParameter("#Id", SqlDbType.Int) { Value = 1 },
new SqlParameter("#Status", SqlDbType.Bit) { Value = true });
Console.WriteLine(data.Count());
}
}
}
of course, this is only Reading, for Insert/Update, similar methods could be created too.
But the complicated part is how to make it dynamic with unknown number of conditions and the relationship between them. So a quick suggestion is use a delegated method or class to do the work. sample (not tested):
public static Dictionary<string, SqlParameter> GetParamsFromInputString(string inputString)
{
var output = new Dictionary<string, SqlParameter>();
// use Regex to translate the input string (something like "[CookingTime] < 30 and [Cost] < 20" ) into a key value pair
// and then build sql parameter and return out
// The key will be the database field while the corresponding value is the sql param with value
return output;
}
public void TestWithInput(string condition)
{
var parameters = GetParamsFromInputString(condition);
// first build up the sql query:
var sql = "SELECT Id, Name from tblMyTable WHERE " + parameters.Select(m => string.Format("{0}={1}", m.Key, m.Value.ParameterName)).Aggregate((m,n) => m + " AND " + n);
using (SqlConnection con = new SqlConnection("connection string here"))
{
var data = ExecuteAdhocQuery(con,
sql,
CommandType.Text,
(x) => new { Id = x.GetInt32(0), Name = x.GetString(1) },
parameters.Select(m => m.Value).ToArray());
}
}
for the static function GetParamsFromInputString, it's just a sample. actually it could be very complicated depending on your needs.
for example, you might want to include the operator (whether it's >, < or <>,...).
and you might also want to include the conjunctions between the conditions, whether it's AND or OR.
Build delegated classes to do the job if it's very complicated.