This is my query
SELECT COUNT(MPRO.OriDes0154) 'QueueCalls' FROM MMProdat.dbo.InstTaWf0154 MPRO WITH(NOLOCK)
WHERE MPRO.Estado0154 = 'QUEUED'
AND F1IdWI02140154<>'VOICEMAIL'
AND F1Camp02930154 = 'Support'
please notice that i have AND F1Camp02930154 = 'Support'
Now I have a list like this:
List<string> compaines = new List<string>();
the values in this list should be in this conidtion AND F1Camp02930154 = 'Support'
for example if the list is empty, i will get an empty result, but if the list has just one value which is Support the query will be
AND F1Camp02930154 = 'Support'
but if the list has two vaules which are Support and Sales then the query will be
AND F1Camp02930154 = 'Support' and `Sales`
how to do that please in c#
where I already have this:
string queryString = "SELECT COUNT(MPRO.OriDes0154) 'QueueCalls' FROM MMProdat.dbo.InstTaWf0154 MPRO WITH(NOLOCK) WHERE MPRO.Estado0154 = 'QUEUED' AND F1IdWI02140154<>'VOICEMAIL'";
Update 1
After # Gordon Linoff comment
I tried this:
List<string> compaines = new List<string>();
string queryString = "SELECT COUNT(MPRO.OriDes0154) 'QueueCalls' FROM MMProdat.dbo.InstTaWf0154 MPRO WITH(NOLOCK) WHERE MPRO.Estado0154 = 'QUEUED' AND F1IdWI02140154<>'VOICEMAIL' AND F1Camp02930154 IN (";
for (int i = 0; i < compaines.Count(); i++) {
queryString += "'" + compaines[i] + "'";
}
queryString += ")";
You can use String.Join() to construct IN () clause, for example :
var companies = new List<string>() { "Support", "Sales" };
string inClause = String.Format(" IN ('{0}')", String.Join("', '", companies));
Console.WriteLine("AND F1Camp02930154" + inClause);
//output :
//AND F1Camp02930154 IN ('Support', 'Sales')
Related
I have a way to write a SqlCommand which includes a dynamic list of parameters.
My challenge is passing each of the new SqlParameter (#Param0, value0), new sqlParameter (#Param1, value1)... could be another 50 SQL parameters. It can be passed as a hard-coded string but passing the sb.ToString() understandably won't work (because of the commas - they are new arguments).
How do I write a loop or similar to pass the correct number of new arguments?
My attempt so far is below:
public ViewResult Index(int? ID)
{
using (var context = new Projects201819Context())
if (ID == null)
{
var sqlCommand = new SqlCommand();
// Array of item numbers - will change and can be longer/shorter, as required.
var SQL0 = "SELECT * FROM [database] WHERE material_id IN ({0})";
var idList = new List<int> { 11, 53, 125};
int[] idListArray = idList.ToArray();
var idParameterList = new List<string>();
var index = 0;
int IL = idList.Count;
// Create a SqlParameter for each element in the array called "#idParam0", "#idParam1"... and add to list idParameterList
foreach (var id in idList)
{
var paramName = "#idParam" + index;
sqlCommand.Parameters.AddWithValue(paramName, id);
idParameterList.Add(paramName);
index++;
}
// Finalise SQL String for datainput - DONE AND WORKS
sqlCommand.CommandText = String.Format(SQL0, string.Join(",", idParameterList));
var newSPList = new List<string>();
var m = 0;
foreach (var id in idList)
{
var SPName = " new SqlParameter(" + "\"" + "#idParam" + m + "\"" + "," + idListArray[m] + ")";
newSPList.Add(SPName);
m++;
}
string HELLO = string.Join(",", newSPList);
string MM = "\"" + sqlCommand.CommandText + "\"" + "," + HELLO;
var datainput = context.materials.SqlQuery(MM);
var data = datainput.ToList();
return View(data);
}
}
where there is an id is fine and not given (the else part of if (id == null)).
The critical bit is the SPName - this successfully adds items to the newSPList list and the string.join returns the exact string I need (HELLO) but I can't then pass this long string as separate arguments - makes complete sense - I just don't know how to work around it!
Thank you for any support!
Let SQL Server do all dirty work. Something like this.
var SQL0 = "SELECT * FROM [database] WHERE material_id IN (select value from string_split('{0}',','))";
var idList = new List<int> { 11, 53, 125};
int[] idListArray = idList.ToArray();
sqlCommand.CommandText = String.Format(SQL0, string.Join(",", idListArray));
// now execute the command
EDIT
More secure and performat way.
var SQL0 = "SELECT * FROM [database] WHERE material_id IN (select value from string_split(#ids,','))";
var idList = new List<int> { 11, 53, 125};
int[] idListArray = idList.ToArray();
sqlCommand.CommandText = SQL0;
sqlCommand.Parameters.Add("#ids", SqlDbTypes.VarChar, -1).Value = string.Join(",", idListArray);
// now execute the command
You cannot pass an array of parameters in that way. SqlQuery from EF6 has an overload that accepts, as second parameter, an array of SqlParameter.
All you have to do is:
SqlParameter[] pms = sqlCommand.Parameters.Cast<SqlParameter>().ToArray();
var datainput = context.materials.SqlQuery(sqlCommand.CommandText, pms);
Of course this means also that a lot of your current code is unnecessary and you can scrap it away
For example, you could write this without an SqlCommand object used just to store parameters and the command text.
var SQL0 = "SELECT * FROM [database] WHERE material_id IN ({0})";
var idList = new List<int> { 11, 53, 125 };
var idParameterList = new List<string>();
var pms = new List<SqlParameter>();
int count = 1;
foreach (var id in idList)
{
var paramName = "#idParam" + count++;
SqlParameter p = new SqlParameter(paramName, SqlDbType.Int);
p.Value = id;
pms.Add(p);
idParameterList.Add(paramName);
}
string cmdText = String.Format(SQL0, string.Join(",", idParameterList));
var datainput = context.materials.SqlQuery(cmdText, pms);
This question already has answers here:
parameterized queries vs. SQL injection
(4 answers)
Closed 6 years ago.
string[] theParms = ['parm1', 'parm2'];
string theQuery = "SELECT something, somethingAgain " +
"FROM aDBTable " +
"WHERE something = '{?}'" +
"AND something <> '{?}'";
I am needing to replace the {?}'s with the defined parms in theParms.
Is there some type of loop in C# that I can use in order to loop through the string and replace each found {?} with the corresponding parm value?
Something like this:
First loop:
SELECT something, somethingAgain
FROM aDBTable
WHERE something = 'parm1' AND something <> '{?}'
Second loop:
SELECT something, somethingAgain
FROM aDBTable
WHERE something = 'parm1' AND something <> 'parm2'
Is there some type of REGEX or common framework function that can do the above?
sql injection check
bool injectionCheckin = new injectionCheck().inCheck(theFinalQuery);
public class injectionCheck
{
public bool inCheck(string queryString)
{
var badWords = new[] {
"EXEC", "EXECUTE", ";", "-", "*", "--", "#",
"UNION", "DROP","DELETE", "UPDATE", "INSERT",
"MASTER", "TABLE", "XP_CMDSHELL", "CREATE",
"XP_FIXEDDRIVES", "SYSCOLUMNS", "SYSOBJECTS",
"BC_HOME_ADDRESS1", "BC_HOME_ADDRESS2", "BC_HOME_CITY", "BC_HOME_COUNTY", "BC_HOME_POSTAL", "BC_MAIL_ADDRESS1",
"BC_MAIL_ADDRESS2", "BC_MAIL_CITY", "BC_MAIL_COUNTY", "BC_MAIL_POSTAL", "BC_MAIL_STATE", "FLSA_STATUS", "GRADE",
"GRADE_ENTRY_DT", "HIGHEST_EDUC_LVL", "LAST_INCREASE_DT", "BC_SALP_DESCR", "BC_SALP_DESCRSHORT", "SAL_ADMIN_PLAN"
};
string pattern = "(?<!\\w)(" + Regex.Escape(badWords[0]);
foreach (var key in badWords.Skip(1))
{
pattern += "|" + Regex.Escape(key);
}
pattern += ")(?!\\w)";
dynamic _tmpCount = Regex.Matches(queryString, pattern, RegexOptions.IgnoreCase).Count;
if (_tmpCount >= 1)
return true;
else
return false;
}
}
Always create Sql-commands by parameterized queries:
using (SqlConnection conn = new SqlConnection(DatabaseConnectionString))
using (SqlCommand cmd = conn.CreateCommand())
{
var #params = new Dictionary<string, object>{
{ "something", myValue },
{ "somethingDifferent", anotherValue },
};
cmd.CommandText = "SELECT something, somethingAgain " +
"FROM aDBTable " +
"WHERE something = #something'" +
"AND something <> #somethingDifferent'";
foreach (KeyValuePair<string, object> item in values)
{
cmd.Parameters.AddWithValue("#" + item.Key, item.Value);
}
DataTable table = new DataTable();
using (var reader = cmd.ExecuteReader())
{
table.Load(reader);
return table;
}
}
}
This prevents all sort of SqlInjection and you won´t any weird checks as yours with the badlist which is quite messy and does not really prevent you, you can easily bypass the list with some escaping for instance. In particular: why do you want to write your own validation when there allready are ready-to-use methods that do exactly what you want?
Why not just use String.Format?
string[] theParms = new string[] { "parm1", "parm2" };
string theQuery = #"SELECT something, somethingAgain
FROM aDBTable
WHERE something = '{0}'
AND something <> '{1}'";
var res = string.Format(theQuery, theParms);
Result:
SELECT something, somethingAgain
FROM aDBTable
WHERE something = 'parm1'
AND something <> 'parm2'
If you want to do it in either case, you could do it without a loopy as follows.
string theQuery = String.Format( "SELECT something, somethingAgain " +
"FROM aDBTable " +
"WHERE something = '{0}'" +
"AND something <> '{1}'",
theParams[0], theParams[1] );
Okay, to avoid Injection and all that, why don't you do it like this:
string[] theParms = // initialization
string theQuery = // initialization
SqlCommand cmd = new SqlCommand(/* enter connection string */, theQuery)
for(int i = 0; i < theParams.Length; i++)
{
int index = cmd.Text.IndexOf("{?}");
if(index > -1)
{
string pName = string.Format("#p{0}", i);
cmd.Text = cmd.Text.Remove(index, 3).Insert(index, pName);
cmd.Parameters.Add(new SqlParameter() { Name = pName, Value = theParms[i] });
}
}
That should avoid any manual injection checks alltogether... at least if you can't get the query pre-compiled and have to load it at runtime. Otherwise just formulate the SqlCommand's text appropriately and you'll not need a loop or anything. Just a simple initialization:
SqlCommand cmd = new SqlCommand(/* enter connection string */, "SELECT something, somethingAgain FROM aDBTable WHERE something = #p0 AND something <> #p1");
cmd.Parameters.Add(new SqlParameter() { Name = "#p0", Value = theParms[0] });
cmd.Parameters.Add(new SqlParameter() { Name = "#p1", Value = theParms[1] });
You can use IndexOf and substrings to find each instance
for(int i = 0; i < theParms.GetLength(0); i++)
{
string[] tempStrings = new string[]{ theQuery.Substring(0,theQuery.IndexOf("{?}") - 1),
theQuery.Substring(theQuery.IndexOf("{?}"), 3),
theQuery.Substring(theQuery.IndexOf("{?}") + 4) }
tempStrings[1] = tempStrings[1].Replace("{?}", theParms[i]);
theQuery = String.Join("", tempStrings);
}
Though seeing as you check for injection afterwards it is definitely much better to use String.Format
You don't have to handle it by yourself. Instead, ADO.NET allows you define parameters and set their values. See the sample here .MSDN
I have a string with values like:
a,b,c,d,e
The idea is to use an sql command to search an array for entries.
The sql is:
select * from pelates where Onoma in (#giorti)
I am turning the a,b,c,d,e to 'a','b','c','d','e' an then i replace the #giorti value with the previus string to fill a datagridview.
The problem is that the datagridview stays empty unless i edit the sql statement and give a value manually like:
select * from pelates where Onoma in ('Bampis')
if i do so the results come like normal. Please advice ,i think there an encoding problem because the data are in Greek
Here is my code:
//Diaxorismos onomaton pou giortazoun
String giorti = label2.Text;
String[] name = giorti.Split(',');
for (int i = 0; i < name.Length; i++)
{
StringBuilder sb = new StringBuilder(name[i]);
sb.Insert(0, "'");
sb.Append("'");
name[i] = sb.ToString();
name[i] = name[i];
}
String finalName = String.Join(",", name);
finalName = finalName.Replace(" ", "");
textBox1.Text = finalName;
//
showPelatesPouGiortazounCommand = login.connection.CreateCommand();
showPelatesPouGiortazounCommand.CommandText = "select * from pelates where Onoma in (#giorti)";
showPelatesPouGiortazounCommand.Parameters.AddWithValue("#giorti", System.Text.Encoding.UTF8.GetBytes(finalName));
getPelatesPouGiortazounAdapter = new MySqlDataAdapter(showPelatesPouGiortazounCommand);
pelatesPouGiortazounDataset = new DataSet();
getPelatesPouGiortazounAdapter.Fill(pelatesPouGiortazounDataset);
dataGridView1.DataSource = pelatesPouGiortazounDataset.Tables[0].DefaultView;
Use FIND_IN_SET function to search in a comma separated list,
or prepare and bind as many parameters as you have values in the string.
select * from pelates where FIND_IN_SET(Onoma, #giorti)
http://dev.mysql.com/doc/refman/5.5/en/string-functions.html#function_find-in-set
Thanks a lot fellows!
With the above addition my code works great!
Here is the final code:
String giorti = label2.Text;
String[] name = giorti.Split(',');
String finalName = label2.Text;
finalName = finalName.Replace(" ", "");
textBox1.Text = finalName;
showPelatesPouGiortazounCommand = login.connection.CreateCommand();
showPelatesPouGiortazounCommand.CommandText = "select * from pelates where FIND_IN_SET(Onoma, #giorti)";
showPelatesPouGiortazounCommand.Parameters.AddWithValue("#giorti", System.Text.Encoding.UTF8.GetBytes(finalName));
getPelatesPouGiortazounAdapter = new MySqlDataAdapter(showPelatesPouGiortazounCommand);
pelatesPouGiortazounDataset = new DataSet();
getPelatesPouGiortazounAdapter.Fill(pelatesPouGiortazounDataset);
dataGridView1.DataSource = pelatesPouGiortazounDataset.Tables[0].DefaultView;
My output query looks like:
select * from Calls where CallerID = "User.Name" and Endpoint in ("C,D,V") order by JoinTime desc;
My C# query string with parameters looks like this:
string SQLQuery = "select * from Calls where CallerID = #UserName and EndpointType in ({0}) order by JoinTime desc";
The code to add the parameters looks like this:
...
string[] Endpoints = new string[] {"C","D","V"}; //EXAMPLE string array
string UserNameStr = "User.Name"; //EXAMPLE string UserNameStr value
...
string[] paramNames = Endpoints.Select((s, i) => "#endpoint" + i.ToString()).ToArray();
string inClause = string.Join(",", paramNames);
using (cmd = new MySqlCommand((string.Format(SQL, inClause)),connection))
{
for (int i = 0; i < paramNames.Length; i++)
{
cmd.Parameters.AddWithValue(paramNames[i], Endpoints[i]);
}
}
cmd.Parameters.Add("#UserName", MySqlDbType.String).Value = UserNameStr;
MySqlDataReader dataReader = cmd.ExecuteReader();
...
But what if I wanted to add another IN operator so the output query would look like this ;
select * from Calls where CallerID = "User.Name" and Endpoint in ("C","D","V") and ConferenceCall in ("D","C") order by JoinTime desc;
How do I do that? Is there some features in Linq that could be used?
Same way you do it the first time:
// endpoints = comma-delimited list of endpoints
// conferenceCalls = comma-delimited list of conference calls
string SQLQuery = "select * from Calls " +
"where CallerID = #UserName and " +
"EndpointType in ({0}) and " +
"ConferenceCall in ({1}) " +
"order by JoinTime desc";
cmd = new MySqlCommand((string.Format(SQL, endpoints, conferenceCalls)),connection);
As noted in comments, be VERY careful that you validate the strings to avoid SQL injection attacks. There's not a direct way to pass a collection as a SQL parameter. There are ways to do it (passing a delimited string and parsing it is the most common I've seen), but if you are in control of setting the value and validate the data then you should be fine.
i have web-application, in the application a user can search by using a single keyword or multiple keyword. i have used every technique but i do not know what is wrong with this code as it do not filter the result and continue adding new result.
the search keywords are seperated by comma, like summer,38,blue these are 3 keywords. the code and structure of the table is give below.
publi override list<result> retrunsearch(string search)
{
string[] search = pQuery.Split(',');
List <result> myresult = new List<result>();
for (int i = 1; i < search.Length; i++)
{
where += " And '%" + search[i] + "%'";
OleDbCommand sqlcmdCommand0 = new OleDbCommand("select Distinct name from table1 where search like '%" + search[0] + "%' " + where + " order by name", sqlcon);
sqlcmdCommand0.CommandType = CommandType.Text;
OleDbDataReader sdaResult0 = sqlcmdCommand0.ExecuteReader();
while (sdaResult0.Read())
{
result restult1= new result();
result1.name = sdaResult0.String(0);
myresult.add(result1);
}
sdaResult0.Close();
}
return myresult;
}
public class result{
public result()
{
}
public string name{get;set;}
}
the structure of the table is:
id name keyword;
1 blue jeans blue;
2 blue jeans 38;
3 blue jeans summer;
4 black jeans black;
5 black jeans 38;
6 black jeans summer;
You are executing a new SELECT statement for each item in the keyword list. Instead, try building the where clause and then executing the select statement:
public override list<result> retrunsearch(string search)
{
string[] search = pQuery.Split(',');
List <result> myresult = new List<result>();
// Build WHERE
for (int i = 1; i < search.Length; i++)
where += " And '%" + search[i] + "%'";
// Now search
OleDbCommand sqlcmdCommand0 = new OleDbCommand("select Distinct name from table1 where search like '%" + search[0] + "%' " + where + " order by name", sqlcon);
sqlcmdCommand0.CommandType = CommandType.Text;
OleDbDataReader sdaResult0 = sqlcmdCommand0.ExecuteReader();
while (sdaResult0.Read())
{
result restult1= new result();
result1.name = sdaResult0.String(0);
result.add(result1);
}
sdaResult0.Close();
return result;
}
A couple of quick notes:
I'm lazy, so I preserved errors in your code such as not declaring the "where" variable.
You might need to use "OR" instead of "AND" in your WHERE clause, depending on how you want your search to work.
The approach you are taking is subject to a SQL injection attack.
You need to refactor your method a bit. Only the query appending should be in the for loop:
public override list<result> retrunsearch(string search)
{
string[] search = pQuery.Split(',');
List <result> myresult = new List<result>();
OleDbCommand cmd = new OleDbCommand("select Distinct name from table1 where search like '%" + search[0] + "%', sqlcon);
cmd.CommandType = CommandType.Text;
for (int i = 1; i < search.Length; i++)
{
cmd.CommandText += " AND search like '%" + search[i] + "%'";
}
cmd.CommandText += " order by name";
OleDbDataReader sdaResult0 = cmd.ExecuteReader();
while (sdaResult0.Read())
{
result restult1= new result();
result1.name = sdaResult0.String(0);
myresult.add(result1);
}
sdaResult0.Close();
return myresult;
}
Second go at retrieving records using one or more keywords. I've added some nicer variable names and formatting along with some syntax tips to help with readability.
public override List<string> Search(string pQuery)
{
string[] keywords = pQuery.Split(',');
List<string> results = new List<string>();
if (keywords.Length == 0)
{
// Code expects at least one keyword - throw exception or return null ?
}
StringBuilder query = new StringBuilder();
query.Append(
string.Format("SELECT DISTINCT name FROM table WHERE keyword LIKE '%{0}%'", keywords[0])
);
// Add extra keywords
if (keywords.Length > 1)
{
for (int i = 1; i < keywords.Length; i++)
{
query.Append(string.Format(" OR keyword LIKE '%{0}%'", keywords[i]));
}
}
// Add order by
query.Append(" ORDER BY name");
using (OleDbCommand command = new OleDbCommand(query.ToString(), sqlcon))
{
command.CommandType = CommandType.Text;
using (OleDbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
results.Add(reader.GetString(0));
}
}
}
return results;
}