我正在用C#构建一些SQL查询.它将根据代码中存储为变量的某些条件而有所不同.
string Query="SELECT * FROM Table1 WHERE 1=1 ";
if (condition1)
Query += "AND Col1=0 ";
if (condition2)
Query += "AND Col2=1 ";
if (condition3)
Query += "AND Col3=2 ";
Run Code Online (Sandbox Code Playgroud)
它有效,但测试1 = 1似乎并不优雅.如果我没有使用它,我必须记住并检查每次是否已经添加"where"关键字到查询.
有更好的解决方案吗?
Ahm*_*IEM 157
将条件保存在列表中:
List<string> conditions = new List<string>();
if (condition1) conditions.Add("Col1=0");
//...
if (conditions.Any())
Query += " WHERE " + string.Join(" AND ", conditions.ToArray());
Run Code Online (Sandbox Code Playgroud)
Cod*_*ter 85
一种解决方案是不通过附加字符串手动编写查询.您可以使用ORM(如Entity Framework)和LINQ to Entities使用语言和框架为您提供的功能:
using (var dbContext = new MyDbContext())
{
IQueryable<Table1Item> query = dbContext.Table1;
if (condition1)
{
query = query.Where(c => c.Col1 == 0);
}
if (condition2)
{
query = query.Where(c => c.Col2 == 1);
}
if (condition3)
{
query = query.Where(c => c.Col3 == 2);
}
PrintResults(query);
}
Run Code Online (Sandbox Code Playgroud)
Ala*_*ber 17
在这个简单的情况下稍微有点过分,但我过去使用的代码与此类似.
创建一个功能
string AddCondition(string clause, string appender, string condition)
{
if (clause.Length <= 0)
{
return String.Format("WHERE {0}",condition);
}
return string.Format("{0} {1} {2}", clause, appender, condition);
}
Run Code Online (Sandbox Code Playgroud)
像这样使用它
string query = "SELECT * FROM Table1 {0}";
string whereClause = string.Empty;
if (condition 1)
whereClause = AddCondition(whereClause, "AND", "Col=1");
if (condition 2)
whereClause = AddCondition(whereClause, "AND", "Col2=2");
string finalQuery = String.Format(query, whereClause);
Run Code Online (Sandbox Code Playgroud)
这样,如果没有找到条件,你甚至不打扰在查询中加载where语句,并在解析sql语句时保存sql server一小秒处理垃圾where子句.
Dar*_*usz 15
还有另一种解决方案,也可能不优雅,但可以解决问题:
String query = "SELECT * FROM Table1";
List<string> conditions = new List<string>();
// ... fill the conditions
string joiner = " WHERE ";
foreach (string condition in conditions) {
query += joiner + condition;
joiner = " AND "
}
Run Code Online (Sandbox Code Playgroud)
对于:
SELECT * FROM Table1,SELECT * FROM Table1 WHERE cond1 AND condNjga*_*fin 10
做这样的事情:
using (var command = connection.CreateCommand())
{
command.CommandText = "SELECT * FROM Table1";
var conditions = "";
if (condition1)
{
conditions += "Col1=@val1 AND ";
command.AddParameter("val1", 1);
}
if (condition2)
{
conditions += "Col2=@val2 AND ";
command.AddParameter("val2", 1);
}
if (condition3)
{
conditions += "Col3=@val3 AND ";
command.AddParameter("val3", 1);
}
if (conditions != "")
command.CommandText += " WHERE " + conditions.Remove(conditions.Length - 5);
}
Run Code Online (Sandbox Code Playgroud)
这是SQL注入安全和恕我直言,它很干净.在Remove()简单地删除最后AND;
如果没有设置条件,设置了一个条件或者设置了多个条件,它都可以工作.
用这个:
string Query="SELECT * FROM Table1 WHERE ";
string QuerySub;
if (condition1) QuerySub+="AND Col1=0 ";
if (condition2) QuerySub+="AND Col2=1 ";
if (condition3) QuerySub+="AND Col3=2 ";
if (QuerySub.StartsWith("AND"))
QuerySub = QuerySub.TrimStart("AND".ToCharArray());
Query = Query + QuerySub;
if (Query.EndsWith("WHERE "))
Query = Query.TrimEnd("WHERE ".ToCharArray());
Run Code Online (Sandbox Code Playgroud)
只需在后面添加两条线.
string Query="SELECT * FROM Table1 WHERE 1=1 ";
if (condition1) Query+="AND Col1=0 ";
if (condition2) Query+="AND Col2=1 ";
if (condition3) Query+="AND Col3=2 ";
Query.Replace("1=1 AND ", "");
Query.Replace(" WHERE 1=1 ", "");
Run Code Online (Sandbox Code Playgroud)
例如
SELECT * FROM Table1 WHERE 1=1 AND Col1=0 AND Col2=1 AND Col3=2
Run Code Online (Sandbox Code Playgroud)
将成为
SELECT * FROM Table1 WHERE Col1=0 AND Col2=1 AND Col3=2
Run Code Online (Sandbox Code Playgroud)
而
SELECT * FROM Table1 WHERE 1=1
Run Code Online (Sandbox Code Playgroud)
将成为
SELECT * FROM Table1
Run Code Online (Sandbox Code Playgroud)
=====================================
感谢您指出此解决方案的缺陷:
"如果由于任何原因,其中一个条件包含文本"1 = 1 AND"或"WHERE 1 = 1",则可能会破坏查询.如果条件包含子查询或尝试检查是否存在某些子查询,则可能出现这种情况例如,列包含此文本.也许这不是您的问题,但您应该记住它......"
为了摆脱这个问题,我们需要区分"主" WHERE 1 = 1和子查询中的那些,这很容易:
只需使"主要" WHERE特别:我会附加一个"$"符号
string Query="SELECT * FROM Table1 WHERE$ 1=1 ";
if (condition1) Query+="AND Col1=0 ";
if (condition2) Query+="AND Col2=1 ";
if (condition3) Query+="AND Col3=2 ";
Run Code Online (Sandbox Code Playgroud)
然后还附加两行:
Query.Replace("WHERE$ 1=1 AND ", "WHERE ");
Query.Replace(" WHERE$ 1=1 ", "");
Run Code Online (Sandbox Code Playgroud)
如果这是SQL Server,您可以使此代码更清晰。
这也假设了已知数量的参数,当我考虑可能性时,这可能是一个糟糕的假设。
在 C# 中,您将使用:
using (SqlConnection conn = new SqlConnection("connection string"))
{
conn.Open();
SqlCommand command = new SqlCommand()
{
CommandText = "dbo.sample_proc",
Connection = conn,
CommandType = CommandType.StoredProcedure
};
if (condition1)
command.Parameters.Add(new SqlParameter("Condition1", condition1Value));
if (condition2)
command.Parameters.Add(new SqlParameter("Condition2", condition2Value));
if (condition3)
command.Parameters.Add(new SqlParameter("Condition3", condition3Value));
IDataReader reader = command.ExecuteReader();
while(reader.Read())
{
}
conn.Close();
}
Run Code Online (Sandbox Code Playgroud)
然后在 SQL 端:
CREATE PROCEDURE dbo.sample_proc
(
--using varchar(50) generically
-- "= NULL" makes them all optional parameters
@Condition1 varchar(50) = NULL
@Condition2 varchar(50) = NULL
@Condition3 varchar(50) = NULL
)
AS
BEGIN
/*
check that the value of the parameter
matches the related column or that the
parameter value was not specified. This
works as long as you are not querying for
a specific column to be null.*/
SELECT *
FROM SampleTable
WHERE (Col1 = @Condition1 OR @Condition1 IS NULL)
AND (Col2 = @Condition2 OR @Condition2 IS NULL)
AND (Col3 = @Condition3 OR @Condition3 IS NULL)
OPTION (RECOMPILE)
--OPTION(RECOMPILE) forces the query plan to remain effectively uncached
END
Run Code Online (Sandbox Code Playgroud)
为什么不使用现有的查询生成器?像Sql Kata之类的东西。
它支持复杂的条件,联接和子查询。
var query = new Query("Users").Where("Score", ">", 100).OrderByDesc("Score").Limit(100);
if(onlyActive)
{
query.Where("Status", "active")
}
// or you can use the when statement
query.When(onlyActive, q => q.Where("Status", "active"))
Run Code Online (Sandbox Code Playgroud)
它适用于Sql Server,MySql和PostgreSql。