【问题标题】:`WHERE … IN @xs`, where @xs parameter is a value list: Supported by ADO.NET?`WHERE ... IN @xs`,其中@xs 参数是一个值列表:ADO.NET 支持吗?
【发布时间】:2013-06-04 13:13:57
【问题描述】:

我正在尝试使用 WHERE … IN @xs 子句创建参数化 ADO.NET 查询,其中 @xs 是可能不连续值的简短列表,例如 (2, 3, 5, 8, 13)。这可以做到吗?如果有,怎么做?

这行不通:

int[] xs = { 2, 3, 5, 8, 13 };  // I've also tried using a List<int> instead
var c = new System.Data.SqlClient.SqlCommand();
c.CommandText = "SELECT … FROM … WHERE … IN @xs";
c.Parameters.AddWithValue("@xs", xs);  // throws ArgumentException due to `values`

System.Data.SqlDbType enumSystem.Data.SqlTypes namespace 中的类型均未表明支持此方案。我必须恢复为动态 SQL(即使用字符串操作手动编写最终 SQL CommandText)吗?

【问题讨论】:

    标签: c# sql ado.net where-in parameterized-query


    【解决方案1】:

    您必须一次构建一个参数:

    int[] xs = { 2, 3, 5, 8, 13 };
    var c = new SqlCommand();
    var parameters = xs.Select((x, i) => string.Concat("@xs", i)).ToList();
    for (var i = 0; i < xs.Count; i++)
    {
        c.Parameters.AddWithValue(parameters[i], xs[i]);
    }
    
    c.CommandText = string.Format(
        "SELECT ... FROM ... WHERE ... IN ({0})", 
        string.Join(", ", parameters)
    );
    

    【讨论】:

    • 使用多个参数@xs0@xs1,……而不只是实际值有什么好处,如果你假设只有几个不同的具体值组合用过吗?
    • 是的,您应该始终使用参数化查询。在您使用整数的特定示例中,它可能是安全的,但否则您的代码容易受到 SQL 注入的攻击。
    • 所以我知道这是出于安全原因,而不是出于性能考虑(SQL Server 能够比非参数化命令更好地缓存参数化命令,或类似的东西)。这回答了我的问题;谢谢!
    【解决方案2】:

    如果您使用的是 SQL Server 2008 或更高版本,则另一种方法可能是使用“表值参数”。更多信息在这里:Arrays and Lists in SQL Server 2008 Using Table-Valued Parameters

    【讨论】:

    • 如果我理解正确的话,这需要1.在SQL Server数据库(CREATE TYPE xsType AS TABLE (x INT))中创建一个用户定义的表类型,2. 将参数的SqlDbType 设置为SqlDbType.StructuredTypeName 设置为xsType3. 构建一个单列表@xs(例如以IEnumerable&lt;SqlDataRecord&gt; 的形式,以及4.IN @xs更改为IN (SELECT x FROM @xs)。对吗?
    • @stakx - 1. 是的。 2. 您并不总是需要设置 TypeName(参见 msdn 链接)。 3. 是的,或者您可以使用更简单的数据表(IMO) 4. 是的。示例:msdn.microsoft.com/en-us/library/bb675163.aspx
    【解决方案3】:

    正如您已经发现的那样:不支持。

    int[] xs = { 2, 3, 5, 8, 13 };
    var c = new System.Data.SqlClient.SqlCommand();
    // this code assumes xs has always at least one item
    var s = new StringBuilder("SELECT … FROM … WHERE … IN (@xs0");
    c.Parameters.AddWithValue("@xs0", xs[0]);  
    for(int i = 1; i < xs.Length; i++)
    {
      s.AppendFormat(",@xs{0}", i);
      c.Parameters.AddWithValue(String.Format("@xs{0}",i), xs[i]);  
    }
    s.Append(")");
    c.CommandText = s.ToString():
    

    【讨论】:

    • +1 用于明确回答我的实际问题(“这是否受支持?”),而接受的答案不这样做。无论如何,我还是选择了另一个答案,因为它的代码更简单,限制更少。尽管如此:感谢您提供有效的解决方案。
    猜你喜欢
    • 2016-04-04
    • 2022-08-15
    • 2011-12-22
    • 1970-01-01
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多