SQL paramaterization WHERE IN not working [duplicate] - c#

This question already has answers here:
Pass Array Parameter in SqlCommand
(11 answers)
Closed 5 months ago.
I have a specific question about the WHERE IN command inside of a parameterized sql query.
Current situation
All the normal queries are working, but on the following query example it goes wrong:
SELECT * FROM table WHERE Id IN(#Ids)
What does this query do?
This query is selecting all items in the table with the specific ids.
The error
# this generates the following string: "1,2,3,4", which gets parsed into the #Ids param
new OleDbParameter("Ids", String.Join(",", objects.Select(c => c.Id.ToString())));
This will generate the folling raw sql query:
# this is the converted sql query after performing the OleDbCommand.ExecuteNonQueryAsync()
# which is not working
SELECT * FROM table WHERE Id IN("1,2,3,4")
# this is the sql query that is working
SELECT * FROM table where Id IN("1", "2", "3", "4")
solution
as you can see, the first example is an array, but is not an array inside of the IN statement. How can I change my code so it will get the working sql query with parameterization?

You could try this
var ids = new char[objects.Count()];
Array.ForEach(ids, x => x = '?');
var idsList = string.Join(',', ids);
var queryString = $"SELECT * FROM table WHERE Id IN ({idsList})";
var command = new OleDbCommand(queryString, connection);
for (int i = 0; i < ids.Length; i++)
{
command.Parameters.Add($"#p{i + 1}", OleDbType.VarChar, 5).Value = objects.ElementAt(i).Id;
}
OleDbDataReader reader = command.ExecuteReader();

Related

MySQL filter by date

I am building a query string like this.
string query = "SELECT * FROM " + table + " where DATE(Date) > " + howFarBack.ToString("yyyy-MM-dd");
Hwowever, when it executes
while (dataReader.Read())
I am seeing Dates well before the howFarBack ????
public List<OHLC> Select(string table, System.DateTime howFarBack)
{
string query = "SELECT * FROM " + table + " where DATE(Date) > " + howFarBack.ToString("yyyy-MM-dd");
//Create a list to store the result
var list = new List<OHLC>();
//Open connection
if (OpenConnection() == true)
{
//Create Command
MySqlCommand cmd = new MySqlCommand(query, connection);
//Create a data reader and Execute the command
MySqlDataReader dataReader = cmd.ExecuteReader();
//Read the data and store them in the list
while (dataReader.Read())
{
var ohlc = new OHLC();
ohlc.Date = (System.DateTime)dataReader[0];
ohlc.Open = Math.Round((double)dataReader[1], 2);
When in doubt, try to debug by examining the resulting SQL query, not the C# code that formats the SQL query.
I would guess that your query lacks single-quote delimiters around the date literal. So it is ultimately a query like:
SELECT * FROM MyTable where DATE(Date) > 2021-11-02
But 2021-11-02 isn't a date, it's an arithmetic expression that evaluates to an integer: 2021 minus 11 minus 2 = 2008. This will certainly match a lot of dates you didn't intend it to.
You could solve this by ensuring that the right type of quotes are around your date literal (it's actually a string literal that is interpreted as a date when compared to a date).
SELECT * FROM MyTable where DATE(Date) > '2021-11-02'
But it's far better to use query parameters, as mentioned in the comment above.
SELECT * FROM MyTable where DATE(Date) > #howFarBack
Then you don't need quotes. In fact you must not use quotes around the parameter placeholder.
See Parameterized Query for MySQL with C# or many other references for using parameters in SQL statements in C#.
Also remember that parameters can only be used in place of a single literal value. You can't use parameters for table or column identifiers, or a list of values, or SQL keywords, etc.

Use value of List<int> inside IN() clause [duplicate]

This question already has answers here:
Pass Array Parameter in SqlCommand
(11 answers)
Parameterize an SQL IN clause
(41 answers)
Closed 4 years ago.
I have a List<int> whose values I want to use inside IN() clause in my query.
I have read many similar post but none of them worked for me yet.
Let's say my table T is:
Id1 (int) | Id2(int)
Query:
Select Id1
From T
where Id2 in (5,7,9,11)
List:
List<int> ls = new List<int>();
ls.add(5);
ls.add(7);
ls.add(9);
ls.add(11);
Now, how to populate this list in my query as no of integers?
Tried so far:
1)
string ls = string.Join(",", Id2.ToArray());
string getId1 = "select Id1 from T where Id2 in (#ls)";
cmd = new SqlCommand(getId1, con);
cmd.Parameters.Add(new SqlParameter("#ls", ls));
Error:
Conversion failed when converting the nvarchar value '5,7,9,11' to
data type int.
2)
var ls = "("
+ String.Join(",", Id2.Select(x => x.ToString()).ToArray())
+ ")";
string getId1 = "select Id1 from T where Id2 in (#ls)";
cmd = new SqlCommand(getId1, con);
cmd.Parameters.Add(new SqlParameter("#ls", ls));
Error:
Conversion failed when converting the nvarchar value '(5,7,9,11)' to
data type int.
Note : I'll prefer the answer without using LINQ unless it's only possible with LINQ
List<int> ls = new List<int>();
ls.Add(5);
ls.Add(7);
ls.Add(9);
ls.Add(11);
string sql = string.Format( "select Id1 from T where Id2 in ({0})", string.Join(",",ls.Select(n=> "#prm"+n).ToArray()));
SqlCommand cmd = new SqlCommand(sql);
foreach(int n in ls){
cmd.Parameters.AddWithValue("#prm"+n, n);
}

C# dynamic parameters in SQL Server query [duplicate]

This question already has answers here:
Multiple Id's in In clause of SQL Query C# [closed]
(2 answers)
Parameterize an SQL IN clause
(41 answers)
How to add parameter in SELECT query for fieldName IN #fieldName construction [duplicate]
(3 answers)
Closed 4 years ago.
I have a problem with calling by SQL Server database. I have this table
and an object with property Groups, which is something like "all nj sk2".
My query in ssms is
SELECT *
FROM Hours
WHERE class_id = 1
AND groups IN ('all', 'nj', 'sk2')
In C# I'm doing something like this
var query = "SELECT * FROM Hours WHERE class_id = #class_id AND groups LIKE (#groups)";
using (var cmd = new SqlCommand(query, conn))
{
cmd.Parameters.AddWithValue("#class_id", User.Current.ClassId);
cmd.Parameters.AddWithValue("#groups", User.Current.Groups.Replace(" ", ", "));
}
The only way I made this work was
var groups = "('" + User.Current.Groups.Replace(" ", "', '").Remove(User.Current.Groups.Length - 2);
//above is ('all', 'nj', 'sk2')
var query = "SELECT * FROM Hours WHERE class_id = #class_id AND groups LIKE " + groups;
using (var cmd = new SqlCommand(query, conn))
{
cmd.Parameters.AddWithValue("#class_id", User.Current.ClassId);
}
But this is not a good solution imo, so if anyone knows what am I doing wrong please help me out. Thanks

SQL Command c# not getting the right results

I'm running the following query
cmd = new SqlCommand("SELECT * FROM addresses WHERE identifier NOT IN(#notIn)", _connector.getMsConnection());
When I view the value notIn and copy this query I get an empty result on my database (which I'm expecting). However when I'm running this code I get 6 results. The content of string notIN is for example
string notIn = "'201619011124027899693E8M2S3WOCKT9G6KHE11' ,'201619011124027899693E8M2S3WOCKT9G6KHE12'"
which combined with
SELECT *
FROM addresses
WHERE identifier NOT IN(#notIn)
Should create
SELECT *
FROM addresses
WHERE identifier NOT IN ('201619011124027899693E8M2S3WOCKT9G6KHE11',
'201619011124027899693E8M2S3WOCKT9G6KHE12' )
which runs as expected.
it should be like this:
cmd = new SqlCommand(string.Format("SELECT * FROM addresses WHERE identifier NOT IN({0})", notIn), _connector.getMsConnection());
This way the value of notIn will be concat to your string query.
Contrary to what the other answers say, concatenating the string to build the SQL is a bad idea, especially since the input values are strings. You open yourself up to SQL injection attacks.
You should be generating multiple parameters for each item in your list.
For example, if you have the input input:
var notIn = new[] { "A1", "B2", "C3" }
You'd want something like
for(var i = 0; i < notIn.Length; i++)
command.AddParamWithValue("p"+i, notIn);
And then you can build the SQL with concatenation (note that we are not concatenating an input here)
var sql = "SELECT * FROM addresses WHERE identifier NOT IN(" + string.Join(",", notIn.Select(i,v) => { "#p" + i; }) + ")";
Which then would look like:
SELECT * FROM addresses WHERE identifier NOT IN (#p0,#p1,#p2)
Alternatively, you could dump the values into a temporary table and do a join.
Note that the above is pseudocode, and may not compile verbatim, but should give you the right idea about how to procede.
It's because, you passed the #notIn as a whole string, which means, the SQL server see it as:
SELECT * FROM addresses WHERE identifier NOT IN('''201619011124027899693E8M2S3WOCKT9G6KHE11'',''201619011124027899693E8M2S3WOCKT9G6KHE12''')
So you got empty result
Try changing the "not in" to where clause and generate the where with C#:
string selectStatement = "SELECT * FROM addresses WHERE";
selectStatement += " identifier != '201619011124027899693E8M2S3WOCKT9G6KHE11' and identifier != '201619011124027899693E8M2S3WOCKT9G6KHE12'";
Or if you really want to use parameterized SQL, try doing it in stored procedure instead.

How to add parameter in SELECT query for fieldName IN #fieldName construction [duplicate]

This question already has answers here:
Pass Array Parameter in SqlCommand
(11 answers)
Closed 7 years ago.
string idVariable = "qwerty";
string sqlQuery = "select id from user where id = #id";
sqlCommand.Parameters.Add("#id", SqlDbType.VarChar).Value = idVariable;
Adding a value for a specific field is ok.
What if I need to have a few ids and IN in WHERE clause?
List<string> ids = new List<string>{"qwe", "asd", "zxc"};
string sqlQuery = "select id from user where id IN #ids";
sqlCommand.Parameters.Add("#ids", SqlDbType.???).Value = ids;
You can't do this directly because the IN operator expcects a list of values, while your parameter is a single value containing a list.
One way to solve it is using a table valued parameter (here is an example), another way is to dynamically create the parameters for the IN as well as the query:
List<string> ids = new List<string>{"qwe", "asd", "zxc"};
string sqlQuery = "select id from user where id IN(";
for(int i=0; i < ids.Count; i++)
{
sqlQuery += "#Id"+ i + ",";
sqlCommand.Parameters.Add("#id" + i, SqlDbType.varchar).Value = ids[i];
}
sqlQuery = sqlQuery.TrimEnd(",") + ")";
You will need to have them added individually.
List<string> ids = new List<string>{"qwe", "asd", "zxc"};
string sqlQuery = "select id from user where id IN (#id1, #id2, #id3)";
sqlCommand.Parameters.Add("#id1", SqlDbType.VarChar).Value = ids[0];
sqlCommand.Parameters.Add("#id2", SqlDbType.VarChar).Value = ids[1];
sqlCommand.Parameters.Add("#id3", SqlDbType.VarChar).Value = ids[2];
Yes you cannot dynamically change the nature of the query. You could write an in with a fixed number of choices and add them as parameters, or you could dynamically build SQL string itself to both add the number of #id parameters and the value for it. Since you are already using a SQL string for your command, this sort of dynamic SQL is not a problem. If you were using a stored procedure this would not be as easy, but you could use a stored proc with a bunch of optional parameters and then only pass as many as you need. Of course you could also use Entity Framework and LINQ to build the query logic and let the provider for LINQ to EF build the raw SQL Query.

Categories