将数组作为值传递到ado.net DBParameter中

时间:2009-12-28 09:59:26

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

我正在开发的项目有很多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,欢迎使用它们的解决方案。

3 个答案:

答案 0 :(得分:4)

对于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)

答案 1 :(得分:1)

看一下这些文章

这是使用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)

答案 2 :(得分:0)

这段代码可以解决问题。您可以创建自己的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.");
            }
        }
    }