This question already has answers here:
IN Operator in OLEDB
(2 answers)
Closed 1 year ago.
I have some data like name,firstname,surname,std,Rollno.
Using C#, I want to convert this into
('name', 'surname', 'std', 'Rollno')
so that I can use this this data to query into the SQL/MySQL DB like -
SELECT *
FROM Table1
WHERE UserCommunicationId IN ('name', 'surname', 'std', 'Rollno');
Instead of
SELECT *
FROM Table1
WHERE UserCommunicationId IN ('name,surname,std,Rollno');
You can try below below logic
public static class SQLQueryExtensions
{
public static string ColumnFormat(this String str)
{
return "(" + //Include first parenthesis
string.Join(", ", str.Split().Select(x => $"'{x}'")) //Add single quote to each column
+ ")"; //Include last parenthesis
}
}
You can do it in one line as well,
var inputStr = "name,firstname,surname,std,Rollno";
var result = "(" + string.Join(", ", inputStr.Split().Select(x => $"'{x}'")) + ")";
Try Online
Use blow logic, will solve your problem.
string inputStr = "name,firstname,surname,std,Rollno";
string result = string.Join(",", inputStr.Split(',').Select(x => string.Format("'{0}'", x)).ToList());
Output = 'name','firstname','surname','std','Rollno'
One approach I can come up is that:
Set the whole string into query as a parameter.
Split it in a WITH query.
LEFT JOIN it in the main query.
NOT NULL to check if there's any hit.
I've wrote an example below, but I am Oracle user so I am not sure if these syntax are right, not even tested, just googled around. Only take it as an reference to the explanation of the idea.
WITH RECURSIVE targets (stringBuffer, word) AS (
SELECT
#Parameter
,NULL
UNION ALL
SELECT
SUBSTRING(stringBuffer, LEAST(LENGTH(SUBSTRING_INDEX(stringBuffer, ',', 1) + 1, LENGTH(stringBuffer)))
,SUBSTRING_INDEX(stringBuffer, ',', 1)
WHERE LENGTH(word) > 0
OR LENGTH(stringBuffer) > 0 -- I am not really sure about these
)
SELECT *
FROM Table1
LEFT JOIN targets ON targets.word = Table1.UserCommunicationId
WHERE targets.word IS NOT NULL;
Then, in C#, set Parameter for your query command in string like this
string s = "name,firstname,surname,std,Rollno";
Edit:
Or, simply:
SELECT *
FROM Table1
WHERE REGEXP_LIKE(UserCommunicationId, #Parameter)
;
While setting the Parameter in C# as:
string s = "name|firstname|surname|std|Rollno";
Notice that if the keywords can be input by user, you still have the problem where user may enter .+ and it responds every data to them as long as there's no other condition added.
But personally, I think there's a potential issue in your design if you really need an unknown length of IN-CLAUSE in your query. If keywords that can be applied are limited in number, you can, rough but it's my team's current criteria, concat the WHERE section keyword by keyword in C#.
Related
I have a list of items with different ids which represent a SQL table's PK values.
Is there any way to build an efficient and safe statement?
Since now I've always prepared a string representing the statement and build it as I traversed the list via a foreach loop.
Here's an example of what I'm doing:
string update = "UPDATE table SET column = 0 WHERE";
foreach (Line l in list)
{
update += " id = " + l.Id + " OR";
}
// To remove last OR
update.Remove(update.Length - 3);
MySqlHelper.ExecuteNonQuery("myConnectionString", update);
Which feels very unsafe and looks very ugly.
Is there a better way for this?
So yeah, in SQL you've got the 'IN' keyword which allows you to specify a set of values.
This should accomplish what you would like (syntax might be iffy, but the idea is there)
var ids = string.Join(',', list.Select(x => x.Id))
string update = $"UPDATE table SET column = 0 WHERE id IN ({ids})";
MySqlHelper.ExecuteNonQuery("myConnectionString", update);
However, the way you're performing your SQL can be considered dangerous (you should be fine as this just looks like ids from a DB, who knows, better to be safe than sorry). Here you're passing parameters straight into your query string, which is a potential risk to SQL injection which is very dangerous. There are ways around this, and using the inbuilt .NET 'SqlCommand' object
https://www.w3schools.com/sql/sql_injection.asp
https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand?view=dotnet-plat-ext-6.0
It would be more efficient to use IN operator:
string update = "UPDATE table SET column = 0 WHERE id IN (";
foreach (Line l in list)
{
update += l.Id + ",";
}
// To remove last comma
update.Remove(update.Length - 1);
// To insert closing bracket
update += ")";
If using .NET Core Framework, see the following library which creates parameters for a WHERE IN. The library is a port from VB.NET which I wrote in Framework 4.7 years ago. Clone the repository, get SqlCoreUtilityLibrary project for creating statements.
Setup.
public void UpdateExample()
{
var identifiers = new List<int>() { 1, 3,20, 2, 45 };
var (actual, exposed) = DataOperations.UpdateExample(
"UPDATE table SET column = 0 WHERE id IN", identifiers);
Console.WriteLine(actual);
Console.WriteLine(exposed);
}
Just enough code to create the parameterizing SQL statement. Note ActualCommandText method is included for development, not for production as it reveals actual values for parameters.
public static (string actual, string exposed) UpdateExample(string commandText, List<int> identifiers)
{
using var cn = new SqlConnection() { ConnectionString = GetSqlConnection() };
using var cmd = new SqlCommand() { Connection = cn };
cmd.CommandText = SqlWhereInParamBuilder.BuildInClause(commandText + " ({0})", "p", identifiers);
cmd.AddParamsToCommand("p", identifiers);
return (cmd.CommandText, cmd.ActualCommandText());
}
For a real app all code would be done in the method above rather than returning the two strings.
Results
UPDATE table SET column = 0 WHERE id IN (#p0,#p1,#p2,#p3,#p4)
UPDATE table SET column = 0 WHERE id IN (1,3,20,2,45)
This question already has answers here:
How to pass a table as parameter to MySqlCommand?
(2 answers)
Closed 6 years ago.
I am working in C# and MySQl in VS2015 to query my database and return a the information in a VARCHAR type column titled "method". However, the query returns the string "method", and not the values of the method column.
below is the code:
string queryOne = "SELECT " + "#columnName" + " FROM log.transactions";
MySqlCommand cmdOne = new MySqlCommand(queryOne, connectionString);
cmdOne.Parameters.AddWithValue("#columnName", "method");
MySqlDataReader dataReaderOne = cmdOne.ExecuteReader();
while (dataReaderOne.Read())
{
Console.WriteLine(dataReaderOne.GetString(0));
}
dataReaderOne.Close();
While this is the output:
method
method
method
.
.
.
.. for the number of rows in the method column. Is this a formatting problem? Is it possible that the configuration of my database is preventing VarChar's from returning correctly? When I change the query to query a column of type INT, it returns the correct values for an INT type column.
You can't parameterize a column name in a select statment. What you're doing is exaclty like saying select 'foo' from log.transactions. It selects the string 'foo' once for each row. You're just sticking a string value in there; it's not parsing the string value as SQL.
What you can do (if you can afford it) is select * from log.transactions, then your C# code can grab the data in whatever column the caller passed you the name of. With a lot of rows you could be dragging a lot of useless junk back from the DB though.
What you want in the code you show, though is just this:
string queryOne = "SELECT method FROM log.transactions";
If you really want to parameterize "method", that's sketchy because of SQL injection vulnerabilities.
string queryOne = "SELECT " + fieldname + " FROM log.transactions";
That looks good until some comedian using your application gives you a value of "0; drop table log.transactions;--" in the textbox. Then you've got troubles. If you ever concatenate a string variable into a SQL string that you're going to execute, you've got to be fanatical about sanitizing it, and even then you want to avoid it any way you can. It's Russian roulette.
Your query formation has to be like if you want to keep your column dynamic.Now pass column name accordingly.
string queryOne = "SELECT " + column_name + " FROM log.transactions";
MySqlCommand cmdOne = new MySqlCommand(queryOne, connectionString);
MySqlDataReader dataReaderOne = cmdOne.ExecuteReader();
while (dataReaderOne.Read())
{
Console.WriteLine(dataReaderOne[column_name]);
}
dataReaderOne.Close();
This is my code
var compainNames = (from row in DTgraph.AsEnumerable()
group row by row.Field<string>("Campaign") into grp
select new
{
CampaignName = grp.Key
}).ToList();
var dataForOneCampaint = DTgraph.Select("Campaign = " + compainNames[i].ToString()).ToList();
where DTgraph is a datatable.
I got this exception:
Cannot interpret token '{' at position 12.
Could you help please?
I debug and i can see that compainNames has 3 strings
the exception in this line
var dataForOneCampaint = DTgraph.Select("Campaign = " + compainNames[i].ToString()).ToList();
DataTable.Select method use the same rules with DataColumn.Expression property for creating filters.
From it's documentation;
User-Defined Values
User-defined values may be used within expressions to be compared with
column values. String values should be enclosed within single
quotation marks (and each single quotation character in a string value
has to be escaped by prepending it with another single quotation
character).
I believe you can use;
var dataForOneCampaint = DTgraph
.Select("Campaign = '" + compainNames[i].ToString() + "'")
.ToList();
Or use String.Format as Felipe mentioned.
Try using the ' char between the string, for sample:
var dataForOneCampaint = DTgraph
.Select(string.Format("Campaign = '{0}'", compainNames[i].ToString()))
.ToList();
I'm trying to fix a problem in an ASP.NET application which uses DataContext.ExecuteQuery to execute sql statement. The query has this part:
LEFT OUTER JOIN dbo.Contacts ON dbo.Accounts.SalesRepId = dbo.Contacts.ContactId WHERE " + string.Join(" AND ", whereClauses) + #"
where "whereClauses" is a List of strings. This way, a search functionality is implemented into the query. Problem appears when an open search is run for a string like "O'Donnel" which obviously run query into an error. I have been asked to fix this problem. My approach was to substitute the where statement with "{0}" in the query and then pass it as a parameter in ExecuteQuery method. What I achieved is:
LEFT OUTER JOIN dbo.Contacts ON dbo.Accounts.SalesRepId = dbo.Contacts.ContactId {0}
var where = "WHERE 1=1";
_db.ExecuteQuery<AccountModel>(query, where)
but it doesn't work? When I substitute the whole where part with just a parameter for it everything is fine:
LEFT OUTER JOIN dbo.Contacts ON dbo.Accounts.SalesRepId = dbo.Contacts.ContactId WHERE 1={0}
var where = "1";
_db.ExecuteQuery<AccountModel>(query, where)
My question - is it then possible to inject the whole where statement dynamically into DataContext.ExecuteQuery method, or can I pass specific parameters only using this method?
Here's the help page for the ExecuteQuery method.
You can't pass the whole where clause as a parameter because a query like select * from myTable #param isn't valid SQL, whereas select * from myTable where myField = #param is valid SQL.
So, in answer to your specific question - no, you can't do this by passing parameters to ExecuteQuery.
However, why not build up the query in code before you pass it to ExecuteQuery?
e.g.
var query = "select * from myTable where 1=1" + string.Join(" AND ", whereClauses);
var result = _db.ExecuteQuery<AccountModel>(query);
I've got the following query that returns 2 records (in DataSet's query builder)
SELECT EmpID, Name, id
FROM Users
WHERE (CAST(id AS Varchar(20)) IN ('5688','5689'))
Now if I do the same query passing the parameter instead from code behind: String param = "'5688','5689'"; it returns null.
WHERE (CAST(id AS Varchar(20)) IN (#param))
I tried taking off the very first and last ', but that did not make a diffrence.
!!!id is a unique PK!!!
Anyone's got a clue?
The solution I found is quite simple, this works like a charm and there's no need for sps or other functions;
SQL:
SELECT whatever
FROM whatever
WHERE (PATINDEX('%''' + CAST(id AS Varchar(20)) + '''%', #param) > 0)
C#:
String param = "'''1234'',''4567'''";
dataTable1 = tableAdapter1.getYourValues(param);
A variable is not allowed in the IN clause.
You are expecting the values as a comma delimited string you could use the split function (user defined and non-standard) to join them with the original tables:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=326300&SiteID=1
For more information you can visit this
('5688','5689') is an array of values.
Defining String param = "'5688','5689'"; and using it as (#param) makes ('5688','5689') a string. Which wont work.
Bibhas is correct. For me this worked:
string param="'1234','4567'"; we can't use param as SQL Parameter(#param).
command = new SqlCommand("SELECT * FROM table WHERE number IN (" + param + ")", connection);
command.ExcecuteReader();