环境:
您好
我可以参数化SQL Server中的where子句吗?
在我的场景中,一旦输入WHERE子句String,应用程序就会将它连接到查询的其他部分并在SQL Server中执行,然后返回结果。
例如,
出于安全原因,我想将整个WHERE CLAUSE作为参数。 但我不知道如何实现。
提前致谢。
答案 0 :(得分:2)
This是如何做到的
string commandText = "UPDATE Sales.Store SET Demographics = @demographics "
+ "WHERE CustomerID = @ID;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(commandText, connection);
command.Parameters.Add("@ID", SqlDbType.Int);
command.Parameters["@ID"].Value = customerID;
// Use AddWithValue to assign Demographics.
// SQL Server will implicitly convert strings into XML.
command.Parameters.AddWithValue("@demographics", demoXml);
try
{
connection.Open();
Int32 rowsAffected = command.ExecuteNonQuery();
Console.WriteLine("RowsAffected: {0}", rowsAffected);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
答案 1 :(得分:1)
作为参数的整个WHERE子句将以任何方式成为sql注入的受害者。为了防止这种情况,你最好:
设置适当的权限。因此,即使在sql注入的情况下,用户也无法访问未授予的任何内容。在这种情况下,@ Dhaval的样本更好,因为在存储过程中封装的dymanic sql生成需要较少的执行权限。
检查语句是否为sql注入。最简单的方法是检查分号以避免批处理中的其他语句。更复杂,更精确的方法是使用t-sql DOM解析器。例如:
using Microsoft.SqlServer.TransactSql.ScriptDom;
TSql110Parser parser = new TSql110Parser(true);
IList<ParseError> errors = null;
var condition = "a > 100; delete from [Recipes]";
var script = parser.Parse(new StringReader("select [RecipeID] from [Recipes] where " + condition), out errors) as TSqlScript;
if (errors.Count > 0)
{
throw new Exception(errors[0].Message);
}
foreach (var batch in script.Batches)
{
if (batch.Statements.Count == 1)
{
var select = batch.Statements[0] as SelectStatement;
if (select != null)
{
QuerySpecification query = select.QueryExpression as QuerySpecification;
if (query.WhereClause is BooleanBinaryExpression)
{
...
}
}
else
{
throw new Exception("Select statement only allowed");
}
}
else
{
throw new Exception("More than one statement detected");
}
}
答案 2 :(得分:0)
您可以在sql server中创建动态查询,并从C#
传递参数像这样的东西
Create Procedure usp_Test
@WhereCond Varchar(max)
AS
Bgein
Set NoCount ON
Declare @SQLQuery AS Varchar(max)
Set @SQLQuery = 'Select * From tblEmployees where ' + @WhereCond
Execute sp_Executesql @SQLQuery
End
执行程序的C#代码
DataSet ds = new DataSet();
using(SqlConnection conn = new SqlConnection("ConnectionString"))
{
SqlCommand sqlComm = new SqlCommand("usp_Test", conn);
sqlComm.Parameters.AddWithValue("@WhereCond", WhereCond);
sqlComm.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = sqlComm;
da.Fill(ds);
}
答案 3 :(得分:0)
我想原来的问题想知道如何从用户的输入中动态创建它,然后使用正确的sql参数来进行查询。
对于sql参数的使用,通常我所做的是使用泛型辅助方法,一个快速示例(未经测试):
public static class SqlHelpers
{
public static IEnumerable<T> ExecuteAdhocQuery<T>(SqlConnection con, string sql, CommandType cmdType, Func<SqlDataReader, T> converter, params SqlParameter[] args)
{
try
{
using (SqlCommand cmd = new SqlCommand(sql, con) { CommandType = cmdType })
{
cmd.Parameters.AddRange(args);
if (con.State != ConnectionState.Open) { con.Open(); }
var ret = new List<T>();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
ret.Add(converter.Invoke(rdr));
}
}
return ret;
}
}
catch (Exception e)
{
// log error?
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
throw e; // handle exception...
}
}
public void Test()
{
using (SqlConnection con = new SqlConnection("connection string here"))
{
var data = ExecuteAdhocQuery(con,
"SELECT ID, Name FROM tblMyTable WHERE ID = @Id and Status = @Status;",
CommandType.Text, (x) => new { Id = x.GetInt32(0), Name = x.GetString(1) },
new SqlParameter("@Id", SqlDbType.Int) { Value = 1 },
new SqlParameter("@Status", SqlDbType.Bit) { Value = true });
Console.WriteLine(data.Count());
}
}
}
当然,这只是阅读,对于插入/更新,也可以创建类似的方法。
但复杂的部分是如何使它具有未知数量的条件和它们之间的关系。因此,快速建议使用委托方法或类来完成工作。样品(未测试):
public static Dictionary<string, SqlParameter> GetParamsFromInputString(string inputString)
{
var output = new Dictionary<string, SqlParameter>();
// use Regex to translate the input string (something like "[CookingTime] < 30 and [Cost] < 20" ) into a key value pair
// and then build sql parameter and return out
// The key will be the database field while the corresponding value is the sql param with value
return output;
}
public void TestWithInput(string condition)
{
var parameters = GetParamsFromInputString(condition);
// first build up the sql query:
var sql = "SELECT Id, Name from tblMyTable WHERE " + parameters.Select(m => string.Format("{0}={1}", m.Key, m.Value.ParameterName)).Aggregate((m,n) => m + " AND " + n);
using (SqlConnection con = new SqlConnection("connection string here"))
{
var data = ExecuteAdhocQuery(con,
sql,
CommandType.Text,
(x) => new { Id = x.GetInt32(0), Name = x.GetString(1) },
parameters.Select(m => m.Value).ToArray());
}
}
对于静态函数GetParamsFromInputString,它只是一个示例。实际上,根据您的需要,它可能非常复杂。
例如,您可能希望包含运算符(无论是&gt;,&lt;或&lt;&gt;,...)。
并且您可能还希望在条件之间包含连词,无论是AND还是OR。
如果它非常复杂,那么构建委托类来完成这项工作。