【问题标题】:How do I translate a List<string> into a SqlParameter for a Sql In statement? [duplicate]如何将 List<string> 转换为 Sql In 语句的 SqlParameter? [复制]
【发布时间】:2010-12-21 18:50:53
【问题描述】:

我似乎对如何使用SqlParameter 执行In 语句感到困惑。到目前为止,我有以下代码:

cmd.CommandText = "Select dscr from system_settings where setting in @settings";
cmd.Connection = conn;
cmd.Parameters.Add(new SqlParameter("@settings", settingList));

reader = cmd.ExecuteReader();

settingsListList&lt;string&gt;。当调用 cmd.ExecuteReader() 时,由于无法将 List&lt;string&gt; 映射到“已知的提供程序类型”,我得到一个 ArgumentException

我如何(安全地)使用SqlCommands 执行In 查询?

【问题讨论】:

  • 您希望将列表转换为哪种 SQL 类型?没有数组...
  • 我需要列表是sql字符串的列表,例如where setting in ('setting1', 'setting2')
  • @KallDrexx,这毫无意义。 SQL 中没有这种数据类型。您可以做的最好的事情是修改您的“CommandText”以自己构建所需的 SQL(在 SQL 中嵌入参数值)。它不能封装在SqlParameter 中。
  • 除非允许执行不安全的 sql。我很难相信没有允许安全 sql in 语句的构造
  • @KirkWoll,他没有尝试插入数组,查询是一个带有预期多值参数的选择。他正试图做这样的事情: set @pCode='''A1'',''A2'',''A3''' Exec ('Select * From Receiving Where Code In (' + @pCode + ') ')

标签: c# sql ado.net sqlcommand


【解决方案1】:

你可以试试这样的:

string sql = "SELECT dscr FROM system_settings WHERE setting IN ({0})";
string[] paramArray = settingList.Select((x, i) => "@settings" + i).ToArray();
cmd.CommandText = string.Format(sql, string.Join(",", paramArray));

for (int i = 0; i < settingList.Count; ++i)
{
    cmd.Parameters.Add(new SqlParameter("@settings" + i, settingList[i]));
}

【讨论】:

  • 由于无法做到我想要的,所以我使用了这种方法。我爱 linq!
  • 这一直有效,直到 settingList.Count = 0,然后你会在 SQL 中得到一个错误,因为 WHERE setting IN () 是无效的语法。表值参数更正确,见 rizzle 的回答。
【解决方案2】:

您似乎试图传递一个多值参数,该 SQL 语法不会达到您的预期。您可能想要传递一个表值参数。

阅读:http://www.sommarskog.se/arrays-in-sql.html#iter-list-of-strings

具体来说:http://www.sommarskog.se/arrays-in-sql-2008.html#ListSqlDataRecord

private static void datatable_example() {

   string [] custids = {"ALFKI", "BONAP", "CACTU", "FRANK"};

   DataTable custid_list = new DataTable();
   custid_list.Columns.Add("custid", typeof(String));

   foreach (string custid in custids) {
      DataRow dr = custid_list.NewRow();
      dr["custid"] = custid;
      custid_list.Rows.Add(dr);
   }

   using(SqlConnection cn = setup_connection()) {
      using(SqlCommand cmd = cn.CreateCommand()) {

         cmd.CommandText =
           @"SELECT C.CustomerID, C.CompanyName
             FROM   Northwind.dbo.Customers C
             WHERE  C.CustomerID IN (SELECT id.custid FROM @custids id)";
         cmd.CommandType = CommandType.Text;

         cmd.Parameters.Add("@custids", SqlDbType.Structured);
         cmd.Parameters["@custids"].Direction = ParameterDirection.Input;
         cmd.Parameters["@custids"].TypeName = "custid_list_tbltype";
         cmd.Parameters["@custids"].Value = custid_list;

         using (SqlDataAdapter da = new SqlDataAdapter(cmd))
         using (DataSet        ds = new DataSet()) {
            da.Fill(ds);
            PrintDataSet(ds);
         }
      }
   }
}

【讨论】:

  • 当然,您在这里跳过的最重要的一点是需要在数据库上创建 custid_list_tbltype 之前这将起作用
【解决方案3】:

我曾经使用自己的函数来创建这样的参数:

public void SomeDataFunction() {    
    ArrayList params = GetParameters(someEntity);
    CommandObject.Parameters.AddRange(parameters.ToArray());
}

public static ArrayList GetParameters(ISomeEntity entity) {
    ArrayList result = new ArrayList {                  
            OleDbUtility.NewDbParam("@Param1", OleDbType.Integer, , entity.Parameter1),
            OleDbUtility.NewDbParam("@Param2", OleDbType.VarChar, 9, entity.Parameter2),
        }
}

public static OleDbParameter NewDbParam(string parameterName, OleDbType dataType,
                    int size, object value) {
    OleDbParameter result = new OleDbParameter(parameterName, dataType, size, string.Empty);
    result.Value = value;
    return result;
}

【讨论】:

    【解决方案4】:

    如果您使用的是 Sql Server 2008 或更高版本,则可以使用表值参数 - 这允许您将值表作为参数传递。在 .net 中,您定义一个“结构化”类型 SqlParameter 并将值设置为实现 IEnumerable 的值。

    在此处查看带有示例的完整 MSDN 参考:http://msdn.microsoft.com/en-us/library/bb675163.aspx

    【讨论】:

      【解决方案5】:

      使用 XML,在这种情况下它非常快。您可以将列表转换为 XML 并简单地传递一个字符串:

      CREATE TABLE #myTempTable
      (   Letter VARCHAR(20) )
      
      INSERT INTO  #myTempTable (Letter) VALUES ('A'), ('B')
      
      Declare @xml XML = '<a>A</a><a>B</a><a>C</a>'
      
      Select * from #myTempTable 
      Where Letter in 
      (Select p.value('.', 'VARCHAR(40)') AS [Letter] from @xml.nodes('//a') as t(p)) 
      
      DROP TABLE #myTempTable
      

      【讨论】:

      • 您还没有指定如何将列表转换为xml。
      【解决方案6】:

      我通常将列表作为逗号分隔的字符串传递,然后使用表值函数将字符串“拆分”成一个表,然后我可以使用该表在另一个查询中加入。

      DECLARE @Settings TABLE (Sid INT)   
      INSERT INTO @Settings(Sid)
      SELECT CAST(Items AS INT) FROM dbo.Split(@SettingsParameter, ',')
      

      当然,除非您使用的是 SQL Server 2008,否则我会使用表值参数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-03
        • 2013-08-26
        • 2020-01-11
        • 2019-07-28
        • 1970-01-01
        相关资源
        最近更新 更多