I am currently trying to build up the where clause of an SqlCommand.
something similar to this
myCommand.CommandText = "SELECT * " +
"FROM TABLE1 " +
"#whereClause";
//I build up the where clause with a StringBuilder
myCommand.Parameters.AddWithValue("#whereClause" theClause.ToString());
But it doesn't seem like this is possible. I got the exception :
SqlException Incorrect syntax near '#whereClause'
The reason I want to do something like this is because I want to avoid X call to the database and this way I leave sorting and filtering to the server.
Is there anyway to do something similar to this?
/edit : The where clause would look something like this WHERE (TABLE1.COL1 = 'the value' OR TABLE1.COL1 = 'another value' OR TABLE1.COL1 = 'this value' ... )
/edit Finaly this was due to a stupid typo error... after I changed to not use the parametrize query. I'll upvote those answer who helped my out. I will mark as answer what was to closer to fix my situation even if it didn't fixed my (stupid) bug
It seems you're trying to add the entire WHERE clause as a parameter - that won't work!
So suppose you need to build something like this
SELECT * from TABLE1 WHERE Field1=#Field1Value and Field2=#Field2Value
And assuming
you have a List<WhereField> of fields to include in the WHERE clause
and that all clauses are ANDed together
and WhereField looks something like this
public class WhereField
{
public string FieldName{get;set;}
public object FieldValue{get;set;}
public string ComparisonOperator{get;set;}
}
then you have something like this:
var whereClause = new StringBuilder();
foreach (var field in WhereFields)
{
whereClause.Append(field.FieldName)
.Append(field.ComparisonOperator)
.Append("#")
.Append(field.FieldName).Append("Value")
.Append (" AND ");
//add the parameter as well:
myCommand.Parameters.AddWithValue("",field.FieldName+"Value");
}
//cleanly close the where clause
whereClause.Append("1=1");
And now you can execute
myCommand.CommandText = "SELECT * " +
"FROM TABLE1 WHERE " + whereClause.ToString();
You can't use a clause (where) with parameters, you are only allowed to use parameters with command.Parameters.
To build a dynamic Where clause, you have to build your query based on conditions and string concatenation and then add the parameters accordingly.
Something like:
sb.Append("SELECT * FROM TABLE1 ");
if (someCondition)
{
sb.Append("WHERE XColumn = #XColumn");
myCommand.Parameters.AddWithValue("#XColumn", "SomeValue");
}
else
{
sb.Append("WHERE YColumn = #YColumn");
myCommand.Parameters.AddWithValue("#YColumn", "SomeOtherValue");
}
myCommand.CommandText = sb.ToString();
May be you need
myCommand.CommandText = "SELECT * " +
"FROM TABLE1 WHERE " +
"#whereClause";
Related
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;
I'm trying to build a dynamic sql query to update a table in SQL Server, like this:
string alan = "SaticiKodu";
DynamicParameters paramStSabit = new DynamicParameters();
string sqlSabit = "UPTADE TBLSTSABIT SET ";
if (alan == "SaticiKodu")
{
sqlSabit += " SATICI_KODU = #SaticiKodu ,";
paramStSabit.Add("SaticiKodu", _msk.SaticiKodu);//_msk.SaticiKodu comes from List<T> in foreach loop
}
if (sqlSabit.Contains("=")) // here I check if I have any column update with '='
{
sqlSabit += "WHERE STOK_KODU = #StokKodu";
paramStSabit.Add("StokKodu", _msk.StokKodu);
sqlSabit= sqlSabit.Replace(",WHERE", " WHERE");
db.Execute(sqlSabit, paramStSabit, transaction: _transaction, commandType: CommandType.Text);
}
I have a list of objects, it has lots of properties but to make example short, here I write only StokKodu and StokAdi. This code throws an error
Incorrect syntax at '='
I think this code should work with Dapper.
How can I make this code work, where is my mistake? Thanks for the help from now.
All i do is changing
string sqlSabit
to
StringBuilder sqlSabit
and instead of join strings with +=, i used sqlSabit.Append(), now code is working. And i tested with string, integer and float typed columns/parameters, no problem.
But couldn't understand why StringBuilder solves the problem.
i have the Following Method:
ServiceType GetWithValidServices(long ServiceTypeID);
and the following Function:
public ServiceType GetWithValidServices(long ServiceTypeID)
{
IQuery query = CurrentSession.CreateQuery("select dl.ServiceType from Service as dl"
+ "where dl.ServiceType.ID = :id and dl.IsValid = true"
+ "order by dl.HavePriority desc");
query.SetInt64("id", ServiceTypeID);
var dlArt = query.UniqueResult<ServiceType>();
return dlArt;
}
In the following Method i call the the above mentioned function:
public ServiceCollection GetService(long ServiceTypeID)
{
ServiceType d = DomainToWebgridMapper.GetWebgridServiceType(DaoFactory.Instance.ServiceTypeDao.GetWithValidService(ServiceTypeID));
return d.Service;
}
My Problem is that the query is not running correctly. I can see the Services but the filter where dl.IsValid is not running, also he do not order the Types by Priority.
I use the where-clause in few other Methods and there it is working fine.
I don't know what is going wrong here. Maybe someone can help me.
Thanks in advance
I think I see what your problem is; it has to do with how you're concatenating the strings to create the query. Consider this for a moment:
string query = "select dl.ServiceType from Service as dl"
+ "where dl.ServiceType.ID = :id and dl.IsValid = true"
+ "order by dl.HavePriority desc";
Because you're not inserting any spaces or line breaks at the beginnings/ends of your strings, what your query turns into is this:
select dl.ServiceType from Service as dlwhere dl.ServiceType.ID = :id and dl.IsValid = trueorder by dl.HavePriority desc
^^^^^^^ ^^^^^^^^^
See where I've marked the problems? To remedy this, add an extra space to the end of all but the last string you're concatenating to make up the query, or use something like a verbatim string literal instead.
IQuery query = CurrentSession.CreateQuery(
"select dl.ServiceType from Service as dl " +
"where dl.ServiceType.ID = :id and dl.IsValid = true " +
"order by dl.HavePriority desc"
);
I have this code:
"SELECT tblschemeprojectpaymentgateway.paymentgatewayid, paymentgatewayname FROM " +
"tblschemeprojectpaymentgateway INNER JOIN tblpaymentgateway ON " +
"tblschemeprojectpaymentgateway.paymentgatewayid = tblpaymentgateway.paymentgatewayid"+
"WHERE tblschemeprojectpaymentgateway.schemeprojectid=`"+
SchemeProjectID.ToString()+"`", SqlConnection1);
sqlcmd.CommandType = CommandType.Text;
SqlConnection1.Open();
Npgsql.NpgsqlDataReader dr = sqlcmd.ExecuteReader();
which queries a Postgresql database. SchemeProjectID is a Guid. This code executes fine with the pgAdmin database query tool, but throws a syntax error in the C# code soemwhere around "tblschemeprojectpaymentgateway".
I have tried the SchemeProjectID in quotes, backtics and just as it is - with and without the .ToString().
I can not figure out what is wrong.
Classic problem when splitting strings over several lines; you're missing the space between tblpaymentgateway.paymentgatewayid and WHERE.
To help avoid missing spaces in strings split over multiple lines, I have found it helpful to use the # symbol before the string to take a multi line string literally. Like such:
string command = #"SELECT tblschemeprojectpaymentgateway.paymentgatewayid, paymentgatewayname FROM
tblschemeprojectpaymentgateway INNER JOIN tblpaymentgateway ON
tblschemeprojectpaymentgateway.paymentgatewayid = tblpaymentgateway.paymentgatewayid
WHERE tblschemeprojectpaymentgateway.schemeprojectid=`" + SchemeProjectID.ToString() + "`";
Also, you may want to look into parameterizing your statements and possibly wrapping them in stored procedures.
You are missing a space on the third line before the WHERE.
"SELECT tblschemeprojectpaymentgateway.paymentgatewayid, paymentgatewayname FROM " +
"tblschemeprojectpaymentgateway INNER JOIN tblpaymentgateway ON " +
"tblschemeprojectpaymentgateway.paymentgatewayid = tblpaymentgateway.paymentgatewayid "+
"WHERE tblschemeprojectpaymentgateway.schemeprojectid=`"+
Ok, I have a list that consists of a bunch of values from a sql query, that part works fine. What I want to do is use the items in that list to tell another query what to look for. So, what it is saying is that, it should return all columns from CMMReports where PartNumber is like %listItem1..2...3%, Any advice?
List<string> ImportedParts = GetImportedPartNumbers();
string query = "SELECT * FROM CMMReports WHERE (RacfId IS NULL OR RacfId = '') AND (FilePath NOT LIKE '%js91162%') AND PartNumber LIKE %" + ImportedParts + "% ORDER BY CreatedOn DESC;";
Not that I condone this as you should be using parameterized queries. However, this should work:
StringBuilder partNumbers = new StringBuilder();
foreach (string queryValue in ImportedParts)
{
string q = "PartNumber LIKE '%" + queryValue + "%'";
if (string.IsNullOrEmpty(partNumbers.ToString())
{
partNumbers.Append(q);
}
else
{
partNumbers.Append(" OR " + q);
}
}
string query = string.Format("SELECT * FROM CMMReports WHERE (RacfId IS NULL OR RacfId = '') " +
"AND (FilePath NOT LIKE '%js91162%') AND ({0}) " +
"ORDER BY CreatedOn DESC;", partNumbers.ToString());
You might look up the IN clouse for SQL that way you get the answer for the parts that SQL Server can find in the database. Using WHERE x = y for all the items means that if one item can't be found the whole query returns nothing.
I would consider doing this in a stored procedure and passing in your list as an Xml parameter.
See the following article for more info on using Xml parameters in a stored proc:
Passing lists to SQL Server 2005 with XML Parameters - By Jon Galloway
Form there you can easily use your list data inside your stored proc using the Xml syntax and treat it almost as another table of data.
Untested, but you should get the idea:
List<string> ImportedParts = GetImportedPartNumbers();
SqlCommand cmd = myConnection.CreateCommand();
cmd.CommandText = "SELECT * FROM CMMReports WHERE (RacfId IS NULL OR RacfId = '') AND (FilePath NOT LIKE '%js91162%') AND (";
int i = 0;
foreach (string part in ImportedParts) {
cmd.AddParameterWithValue("#param" + i.ToString(), "%" + part + "%");
if (i != 0) cmd.CommandText += " OR"
cmd.CommandText += " PartNumber LIKE #param" + i.ToString();
i++;
}
cmd.CommandText += ") ORDER BY CreatedOn DESC;";
This solution uses a parameterized query instead of just appending strings in the SQL, which is considered a potential security risk.