Passing parameter to SQL select statement IN clause acts weird. - c#

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();

Related

C# Extension method to Convert into the comma separated [duplicate]

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#.

Dapper can't recognize wildcard param in the single quotes

I am trying to get indexes fragmentation info from database.
Here the dapper sql query:
var result = await _dbConnection.QueryAsync<IndexFragmentationModel>($#"
select
a.index_id as Id, name as Name, avg_fragmentation_in_percent as FragmentationPercent
from sys.dm_db_index_physical_stats (DB_ID(N'#dbName'), OBJECT_ID(N'#tableName'), null, null, null) as a
join sys.indexes as b on a.object_id = b.object_id and a.index_id = b.index_id;
", new
{
dbName = dbName,
tableName = tableName
});
return result.ToList();
Parameters are not passing the the places where they are expected.
Could anybody please suggest - maybe there is another way to pass them ?
You're using the literal strings "#dbName" and "#tableName", not the parameters' values.
Remove the N' and ' that surround them.

How to use every word of a string in WHERE clause?

I am facing a problem , I have a query in SQL Server 2014, The query result should be based on a WHERE clause that takes a string from a C# CheckedListBox.
I have the string in this form (the following values are for example only) :-
cat,dog,bird,duck
And inside the database the records look like this:-
dog cat-dog cat-dog-duck bird-dog-duck etc...
I have tried this :-
DECLARE #animals nvarchar(max) = 'dog,bird,cat'
select x,y,z WHERE CHARINDEX(animals, replace(#animals,',',' ')) > 0
The result would show rows with only ONE SINGLE VALUE like dog cat bird But it wouldn't show rows with values like dog-cat dog-cat-bird etc! it just shows rows with one single word from #animals string.
How can I select all rows where column animals contains either a word or more from #animals string.
Thanks in advance...
You should create a temp table for store all searching value or you should create a temp table from the comma separated variable for the example visit Query for convert CSV values into temp table. Then use inner join for filter records from your table like below.
declare #temp table (animal varchar(50))
insert into #temp values ('cat')
insert into #temp values ('dog')
insert into #temp values ('bird')
select * from SomeTable a
inner join #temp t on a.Column like '%' + t.animal + '%'
Make stored procedure for that query and call it from C#.
And inside the database the records look like this:-
dog cat-dog cat-dog-duck bird-dog-duck etc...
There is the source of your problems. Before reading anything else I wrote in my answer, you should read Is storing a delimited list in a database column really that bad?, where you will see a lot of reasons why the answer to this question is Absolutely yes!.
Once you're done with that, the solution to the problem should be as obvious to you as it is to me - Fix the database structure - meaning remove that column storing delimited data and replace it with a table referenced by a many-to-many relationship to your existing table, that will hold the animals data for you.
The first part of the solution is using a table valued parameter instead of sending a delimited string to the database.
There are plenty of examples on how to do this on stackoverflow - like here and there.
Once you've done that, you can use a hack with like as a workaround, in case you can't change the database structure:
SELECT <ColumnsList>
FROM <TableName> As T
JOIN #TVP As TVP
ON '-' + T.Animals +'-' LIKE '%-' + TPV.Animal +'-%'
Note I've added the delimiter to both ends of both columns.
If you can change the structure you will have a query like this:
SELECT <ColumnsList>
FROM <TableName> As T
JOIN TableToAnimals AS TTA
ON T.Id = TTA.TableId
JOIN Aniamls AS A
ON TTA.AnimalId = A.Id
JOIN #TVP As TVP
ON A.Name = TVP.Animal
You should take a look at Table valued parameters, it will let you send in a table of values as a parameter from C# to SQL. You make a table with "animals" and then make a sub-select in your Stored Proc.
See example code from link below, shows how to pass the parameter:
// Assumes connection is an open SqlConnection object.
using (connection)
{
// Create a DataTable with the modified rows.
DataTable addedCategories = CategoriesDataTable.GetChanges(DataRowState.Added);
// Configure the SqlCommand and SqlParameter.
SqlCommand insertCommand = new SqlCommand("usp_InsertCategories", connection);
insertCommand.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue("#tvpNewCategories", addedCategories);
tvpParam.SqlDbType = SqlDbType.Structured;
// Execute the command.
insertCommand.ExecuteNonQuery();
}
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters
For anyone who has the same problem. I have found the solution for this on SQL Server. Use the Full Text Search and your problem is easily solved. It's awesome.
Check the following link :-
https://learn.microsoft.com/en-us/sql/relational-databases/search/get-started-with-full-text-search?view=sql-server-2017
use like this:
var query = string.Empty;
var index=0;
foreach(var animal in animals) {
if (query.Length>0) {
query +=" and ";
}
var paramName = "#animalName" + index++;
query +="(animals like " + paramName + " or animals like '%' + " + paramName + " or animals like " + paramName + " + '%' or animals like '%' + " + paramName + " + '%')";
SqlParameter thisParam = new SqlParameter(paramName, animal);
command.Parameters.Add(thisParam);
}
command.CommandText = "select * from tableName WHERE " + query;

MySQL Query Returns Parameter Column Name [duplicate]

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();

ASP.NET Passing apostrophes in Parameter

So I have my SqlDataSource with a SelectQuery defined as follows:
SELECT * FROM table
WHERE UserName IN (#EmployeesIn);
With #EmployeesIn coming from a session variable Session["EmployeesIn"]. During Page_Load I'm taking an ArrayList members and putting the results into a string and setting the session variable:
string employeesIn = "";
foreach (string s in members)
{
employeesIn = employeesIn + "'" + s + "',";
}
employeesIn = employeesIn.TrimEnd(',');
Session["EmployeesIn"] = employeesIn;
Writing the output to the console I can see the value of the parameter #EmployeesIn
#EmployeesIn = 'bob', 'joe'
However, I'm getting zero results back ... and after monitoring from the database level I see the parameter is coming in as:
'''bob'',''joe'''
Then again if I just pass in one employee, I get results back from the SQL as expected and the parameter is passed correctly as just 'bob'. I suppose this is some safety that .NET provides against SQL injection attacks, however what's the safe way around this?
You should absolutely use parameters for this, instead of including the values within the SQL itself. You can just generate the names for the parameters, so if you had three entries you'd generate SQL of:
SELECT * FROM table WHERE UserName IN (#p0, #p1, #p2)
and then fill in those three parameters from the three values.
// Or create the command earlier, of course
List<SqlParameter> parameters = new List<SqlParameter>();
StringBuilder inClause = new StringBuilder("(");
for (int i = 0; i < members.Count; i++)
{
string parameterName = "#p" + i;
inClause.Append(parameterName);
if (i != members.Count - 1)
{
inClause.Append(", ");
}
// Adjust data type as per schema
SqlParameter parameter = new SqlParameter(parameterName, SqlDbType.NVarChar);
parameter.Value = members[i];
parameters.Add(parameter);
}
inClause.Append(")");
// Now use inClause in the SQL, and parameters in the command parameters
I think you have three options:
Comma separated values - you can pass single parameter value as CSVs and split them out in the stored procedure. I don't like this idea ... too many limitations.
XML - you can pass an XML string into the stored procedure and open it as a table using OPENXML. This will give you a table that you can use to do joins, inserts, etc., onto other tables.
Table-Valued Parameters
The better way would be to user your members array to build the query using a parameter list:
SELECT * FROM table
WHERE UserName IN (#EmployeesIn1, #EmployeesIn2, #EmployeesIn3, ... n);
Then loop through your member list, adding the parameters as necessary.
The first thing I noticed was how you're making you're comma demilited list. Try this out:
string employeesIn = string.Join(",", members.Select(x => string.format("'{0}'", x)).ToArray());
As for the parameter, you need to rethink your approach. Have you looked at table value parameters?
SQL Parameters can only represent a single value, you can however pass in multiple parameters such as:
var emps = members.Select( (e,i) => "#EMPLOYEE" + i).ToArray();
string sqlQuery = "SELECT * FROM table WHERE ";
sqlQuery+=string.Format("UserName IN ({0})", string.Join(",", emps));
//add SQL parameters used in query
for (int i = 0; i < members.Count; ++i)
{
parameters.Parameters.Add(new SqlParameter("#EMPLOYEE" + i, members[i]));
}

Categories

Resources