将List <int>添加到mysql参数</int>

时间:2011-04-15 19:18:39

标签: c# .net mysql mysql-connector mysql-parameter

我有关于.NET连接器的MySqlParameter的问题。

我有这个问题:

SELECT * FROM table WHERE id IN (@parameter)

MySqlParameter是:

intArray = new List<int>(){1,2,3,4};

...connection.Command.Parameters.AddWithValue("parameter", intArray);

这可能吗? 是否可以将int数组传递给单个MySqlParameter? 另一个解决方案是将int数组转换为类似“1,2,3,4”的字符串,但是当我将它传递给MySqlParameter并将其识别为字符串时,它会像sql查询一样放入“1 \,2 \,3 \,4”,这不会返回预期的值。

@ UPDATE:似乎mysql连接器团队应该更加努力。

9 个答案:

答案 0 :(得分:15)

  

当我将它传递给MySqlParameter并将其识别为字符串时,它会在“1 \,2 \,3 \,4”之类的sql查询中输入,这不会返回预期的值。

我昨晚遇到了这个问题。我发现FIND_IN_SET在这里工作:

SELECT * FROM table WHERE FIND_IN_SET(id, @parameter) != 0
...
intArray = new List<int>(){1,2,3,4};
conn.Command.Parameters.AddWithValue("parameter", string.Join(",", intArray));

显然这有一些长度限制(我发现你的帖子正在寻找替代解决方案),但这可能适合你。

答案 1 :(得分:5)

参数不适用于IN。我总是在查询本身中嵌入诸如字符串之类的东西。虽然这通常被认为是错误的形式,因为SQL注入,如果您从强类型数字列表构造查询,那么任何外部输入都不可能以有意义的方式破坏它。

答案 2 :(得分:3)

你将不得不迭代你的数组并自己创建列表

// no parameters
var sb = new StringBuilder();
for(int i=0;i<intArray.Length;i++)
{
    sb.Append(intArray[i] + ",");// no SQL injection they are numbers
}
if (sb.Length>0) {sb.Length-=1;}
string sql = "SELECT * FROM table WHERE id IN (" + sb.ToString() + ")";

更新:仔细考虑了这个问题后,我将回到原来的答案(下面),即使用参数。构建查询的优化以及数据库引擎可以支持的任何内容都取决于您。

// no parameters
var sb = new StringBuilder();
for(int i=0;i<intArray.Length;i++)
{
    sb.AppendFormat("p{0},", i);// no SQL injection they are numbers
    connection.Command.Parameters.AddWithValue("p"+i, intArray[i]);
}
if (sb.Length>0) {sb.Length-=1;}
string sql = "SELECT * FROM table WHERE id IN (" + sb.ToString() + ")";

答案 3 :(得分:2)

这里有几个选项(按优先顺序排列):

  1. 使用支持table valued parameters的数据库。这是获取所需语法的唯一方法。
  2. 数据必须来自某个地方:数据库,用户操作或计算机生成的源。

    • 如果数据已存在于您的数据库中,请改用子查询。
    • 对于其他计算机生成的数据,请使用BULK INSERT,SqlBulkCopy或数据库的首选批量导入工具。
    • 如果它是由用户创建的,请将其添加到每个单独用户操作上的单独表中,然后使用子查询。

      这方面的一个例子是购物车。用户可以选择要购买的多个项目。而不是将这些项目保留在应用程序中,并且需要在签出时一次性将所有项目添加到订单中,然后在用户选择或更改数据库时将每个项目添加到数据库中的表格。

  3. 有一个sql用户定义的函数,它将字符串参数解包到表中,并将该表作为可以与IN()表达式一起使用的集合返回。有关其工作原理的详细信息,请参阅下面的链接文章。
  4. 在客户端上动态构建字符串列表或参数列表(如其他答案所示)。请注意,这是我的至少首选选项。
  5. 关于这个主题的最终(我的意思是权威)工作在这里:

    http://www.sommarskog.se/arrays-in-sql.html

    文章很长,但是很好。作者是一名SQL服务器专家,但整体上的概念也适用于MySQL。

答案 4 :(得分:1)

据我所知,你不能提供任何数组作为预处理语句的参数。 IN()不支持将参数作为数组。

答案 5 :(得分:0)

我认为你没有办法像这样添加它们,但也许你可以遍历列表并动态生成查询。

例如:

var intArray = new List<int>(){1,2,3,4};
if (intArray.Count > 0) {
    var query = "SELECT * FROM table WHERE id IN (";
    for (int i = 0; i < intArray.Count; i++) {
        //Append the parameter to the query
        //Note: I'm not sure if mysql uses "@" but you can replace this if needed
        query += "@num" + i + ",";
        //Add the value to the parameters collection
        ...connection.Command.Parameters.AddWithValue("num" + i, intArray[i]);
    }
    //Remove the last comma and add the closing bracket
    query = query.Substring(0, query.Length - 1) + ");";
    //Execute the query here
}

这样,您甚至可以使用不同类型的列表,并且仍然可以获得参数化查询的好处。但是,我不知道大型列表是否存在性能问题,但我怀疑情况会是这样。

答案 6 :(得分:0)

这对于大型列表不适用,但是如果 将列表作为参数传递,那么我发现的唯一是有效的。

而不是

SELECT * FROM table WHERE id IN (@parameter)

你必须这样做:

SELECT *
FROM table
WHERE INSTR(','+@parameter+',', ','+CAST(the_column AS CHAR) + ',')

然后,您可以使用string.Join(",", intArray)

传递您的列表

这是一个kludge,但它的确有效。

答案 7 :(得分:0)

来自Mud的答案仅适用于参数列表中的第一个int。这意味着&#3; 2,1,3,4&#39;如果id为1,则无法工作。

请参阅FIND_IN_SET() vs IN()

现在还没有评论,但也看到了Matt Ellen的回答。 会编辑他的答案,但不能。 INSTR似乎不适用于具有多个id的WHERE情况(仅在结果上返回)。

但是将INSTR替换为LOCATE会使他的解决方案正常工作(添加String.Join(",", intArray)作为参数)...向我投票:

LOCATE(CONCAT(',' , CAST(id AS CHAR) , ',') , CONCAT(',' , CAST(@paramter AS CHAR) , ',')) <> 0

答案 8 :(得分:0)

基于Richard的答案,我想出了一种避免SQL注入的类似方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using Azure.Storage.Blobs;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using System.IO;

namespace Console_Workstation
{
    public class Azure_Storage_Connection
    {
        public static void Main()
        {
            string connstring = ConfigurationManager.ConnectionStrings["AzureStorageAccount"].ConnectionString;
            string localFolder = ConfigurationManager.AppSettings["sourceFolder"];
            string destContainer = ConfigurationManager.AppSettings["destContainer"];
                            
            // Connect to container
            BlobContainerClient blobContainer = new BlobContainerClient(connstring,destContainer);
            blobContainer.CreateIfNotExists();
    
            // Connect to Blob into the container
            BlobClient blob = blobContainer.GetBlobClient(destContainer);
    
            // Upload Local file
            blob.Upload(@"C:\Users\AbdulHameedM\Desktop\LocalFolder\Mapper.xlsx");
        }
            
    }
}

您可以通过以下方式调用它:

private MySqlCommand GetCommandWithIn(string sql, string sqlParam, ICollection<string> list)
{
    var command = new MySqlCommand(string.Empty, connection);
    var i = 0;
    var parameters = new List<string>(list.Count);

    foreach (var element in list)
    {
        var parameter = $"p{i++}";
        parameters.Add($"@{parameter}");
        command.Parameters.AddWithValue(parameter, element);
    }

    command.CommandText = sql.Replace(sqlParam, string.Join(',', parameters));

    return command;
}

请记住要检查是否有空列表,以避免var types = new List<string> { "Type1", "Type2" }; var sql = "SELECT * FROM TABLE WHERE Type IN (@Type)" using var command = GetCommandWithIn(sql, "@Type", types);