在C#

时间:2015-11-02 03:13:09

标签: c# sql sql-server parameters sql-injection

我有以下要运行的SQL语句:

string sql = @"DECLARE @a udt;" +
              "INSERT INTO @a (id) VALUES @params;";

我有以下整数数组:

int[] array1 = {10,20,30,40,50,60};

重要的是不要在我的程序中上面的数组大小是动态的。

我想将数组中的值添加到SQL语句中的@params,以便在SqlCommand中执行的SQL如下所示:

sql = @"DECLARE @a udt;" +
       "INSERT INTO @a (id) VALUES (10),(20),(30),(40),(50),(60);" +
       "EXEC sp @a;";

我在其他人中尝试了以下内容并继续获得例外:

SqlConnection con = new SqlConnection("connectionString");
SqlCommand cmnd = new SqlCommand(sql, con);

for (int i = 0; i < array1.Count; i++)
{
    cmnd.Parameters.AddWithValue("@params" , array1[i]);
}

con.open().
cmnd.ExecuteNonQuery();

请有人解释我做错了什么。我还需要确保防止SQL注入。

3 个答案:

答案 0 :(得分:1)

根据@params参数加入Int数组进行格式化:

int[] intArr = { 10, 20, 30 };
string intStr = string.Join(",", intArr.Select(i => "(" + i.ToString() + ")"));

intStr的格式为(10),(20),(30),您传递给sql。创建动态语句并执行它。

-- declared here for sample
declare @params varchar(50) = '(10),(20),(30)'

declare @sql varchar(max) = 
    'declare @a table (id int)' + ';' +
    'insert into @a (id) values ' + @params + ';' +
    'exec sp @a'

exec (@sql)

答案 1 :(得分:1)

您可以为values子句使用generate dynamic SQL。这将导致一些性能开销,具体取决于由于计划缓存重用不良而运行此代码的频率。

我会将数组作为分隔字符串传递给过程,并使用SQL字符串拆分器将字符串转换为表。这允许您将单个参数传递给过程并可能绕过UDT。

网络搜索提供了各种字符串分割器。你发现使用循环的任何东西都会很慢,但会起作用。我个人更喜欢Jeff Moden的内联表值函数[DelimitedSplit8K](需要免费注册,但我觉得非常值得),这可能是最快的TSQL字符串分割器。

任何拆分器的使用方法与此类似:

DECLARE @a udt;
INSERT INTO @a([id])
SELECT [Item]
FROM [dbo].[DelimitedSplit8K](@params)

这会将{10,20,30,40,50,60}转换为每行一个值的表。

另一种用途是加入:

SELECT 
    [col1],
    [col2],
    [ItemNumber] -- position in array
FROM [dbo].[MyTable] A
INNER JOIN [dbo].[DelimitedSplit8K](@params) B
ON       A.[col3] = B.[Item] -- join on array value

答案 2 :(得分:1)

您已接近解决方案,但需要在sql字符串中显式引用每个数组索引参数。例如:

    List<int> tests = new List<int>() { 10, 11, 12};
    var command = new MySqlCommand();
    List<string> parameterNames = new List<string>();
    for (int i = 0; i < tests.Count; i++)
    {
            string parameterName = String.Format("@test{0}", i);
            command.Parameters.AddWithValue(parameterName, tests[i]);
            parameterNames.Add("(" + parameterName + ")");
    }
    string insertSql = @"insert into test(id) values {0}";
    command.CommandText = String.Format(insertSql, String.Join(", ", parameterNames));
    command.Connection = connection;

    int result = command.ExecuteNonQuery();

生成的sql命令文本为:

"insert into test(id) values (@test0), (@test1), (@test2)"