【问题标题】:Pass an array as value in an ado.net DBParameter将数组作为值传递给 ado.net DBParameter
【发布时间】:2010-12-30 10:31:39
【问题描述】:

我正在从事的项目有很多 IN 查询,例如:

SELECT something, anotherthing
FROM atable
WHERE something IN (value1, value2, value3)

这是一个在 IN 部分具有 3 个参数的查询示例,但可以使用 1 或 2 或 5 或 10 或 ... 参数执行相同的查询。 问题是每个查询在数据库中都有另一个执行计划,这使得它变慢了。

我想要这样的查询:

SELECT something, anotherthing
FROM atable
WHERE something IN (@value1, @value2, @value3)

或者这个:

SELECT something, anotherthing
FROM atable
WHERE something IN (@values)

我已经使用一些辅助函数完成了第一个查询,但是对于每个参数数量我仍然有不同的执行计划。这可以通过第二个来解决。

将数组作为数据库参数传递的最佳方式是什么?我正在使用 Oracle 和 SQL Server,欢迎使用它们的解决方案。

【问题讨论】:

    标签: c# sql-server oracle ado.net


    【解决方案1】:

    对于 SQL-Server,有两种常用方法。第三个要避免的选项是传入varchar 并将其与IN 连接成动态SQL 语句——这是一个明显的注入攻击面。

    合理的选择:

    • 传入 varchar 并使用 UDF 在分隔符 (like in this question) 上拆分数据,可能是逗号、管道、制表符等。加入结果:

      SELECT something, anotherthing
      FROM atable a
      INNER JOIN dbo.SplitUDF(@values) udf
              ON udf.Value = a.something
      
    • 使用 table-valued-parameter (SQL2008) 并直接加入(避免使用 UDF)

    【讨论】:

    • 不幸的是,我必须支持 SQL Server 2000 和 2005,没有适合我的表值参数。
    【解决方案2】:

    看看这些文章

    这是使用XML类型创建列表的示例

    --Split
    DECLARE @textXML XML
    DECLARE @data NVARCHAR(MAX), 
            @delimiter NVARCHAR(5)
    
    SELECT  @data = 'A,B,C',
            @delimiter = ','
    
    SELECT    @textXML = CAST('<d>' + REPLACE(@data, @delimiter, '</d><d>') + '</d>' AS XML)
    SELECT  T.split.value('.', 'nvarchar(max)') AS data
    FROM    @textXML.nodes('/d') T(split)
    

    【讨论】:

      【解决方案3】:

      这段代码可以解决问题。您可以创建自己的 BuildQuery(???) 函数。

          public void RemoveDependencies(int versionID, int[] deps)
          {
              if (versionID <= 0)
                  throw new ArgumentException();
              if (deps == null)
                  throw new ArgumentNullException();
              if (deps.Length <= 0)
                  throw new ArgumentException();
      
              SqlCommand cmd = new SqlCommand();
              string query = "DELETE FROM Dependencies WHERE version_id = @VersionId AND dep_version_id IN (";
              int n = deps.Length;
              string key;
              for (int i = 0; i < n; i++)
              {
                  if (deps[i] <= 0)
                      throw new ArgumentException();
                  key = String.Format("@dep{0}", i);
                  query += key;
                  cmd.Parameters.AddWithValue(key, deps[i]);
                  if (i < n - 1)
                  {
                       query += ", ";
                  }
              }
              query += ")";
              cmd.Parameters.AddWithValue("@VersionId", versionID);
              cmd.CommandText = query;
              using (SqlConnection con = GetSqlConnection())
              {
                  con.Open();
                  cmd.Connection = con;
                  if (cmd.ExecuteNonQuery() <= 0)
                  {
                      throw new ArgumentException("No rows affected! Illegal id.");
                  }
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-10-06
        • 1970-01-01
        • 1970-01-01
        • 2017-10-10
        • 2017-01-26
        • 2020-03-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多