【问题标题】:SQL Server query using Parameters for an IN Clause使用 IN 子句的参数的 SQL Server 查询
【发布时间】:2017-01-12 22:46:48
【问题描述】:

我正在尝试使用IN 子句进行更新,但我似乎无法让它工作。我的iArr 创建了一个用逗号分隔的数字列表,理论上,一旦括在括号中,它应该会更新,但它似乎不起作用。一直报错

将 nvarchar 值 '111111, 222222, 333333' 转换为数据类型 int 时转换失败。

知道如何解决这个问题吗?完整代码如下:

    Dim iArr As String
    iArr = ""
    For i As Integer = 0 To ufReview.InvoiceGrid.Rows.Count - 1
        iArr = iArr & ufReview.InvoiceGrid.Rows(i).Cells(0).Value & ", "
    Next i
    iArr = Left(iArr, Len(iArr) - 2)

    Dim SQL_Arr As String = _
            <SQL>
               UPDATE SCInv SET Inv_Transfer_Date = @UpdateCommand WHERE Inv_Num IN (@Array)
            </SQL>

    Dim cnt As New SqlConnection()
    Dim cmd As New SqlCommand()
    cnt.ConnectionString = "Data Source=SERVERNAME;Initial Catalog=CAT;User ID=USERID;Password=PASSWORD"
    Try
        cnt.Open()
        cmd.Connection = cnt
        cmd.CommandText = SQL_Arr
        cmd.Parameters.Clear()
        cmd.Parameters.AddWithValue("@UpdateCommand", UpdateCommand)
        cmd.Parameters.AddWithValue("@Array", iArr)
        Dim RACount As Integer = cmd.ExecuteNonQuery()
        MsgBox("The following Summary Numbers are now marked as " & UpdateFeedback & ": " & vbCrLf & iArr _
               & vbCrLf & vbCrLf & "(" & RACount & " row(s) affected)", vbOKOnly + vbInformation, "Tesseract")
    Catch ex As Exception
        MsgBox("Failed to update, please try again" & vbCrLf & vbCrLf & ex.Message, vbOKOnly + vbCritical, "SQL Error")
    End Try
    cnt.Close()
    cnt.Dispose()

【问题讨论】:

  • 这不是答案,但您可能应该参数化您的 WHERE 子句。我认为 SQL 注入器会用你目前拥有的东西在嘴里冒泡。
  • 首先检查该提供程序是否会接受参数数组。我总是不得不格式化和扩展它们。
  • 尝试将您的数组从 ('item1, item2') 更改为 ('item1', 'item2')
  • @ProGrammer 我尝试了这个,但它仍然没有用。当我将代码更改为此它可以工作但是我想尝试并坚持使用参数。由于某种原因,它似乎只在使用参数时失败... Dim SQL_Arr As String = _ UPDATE SCInv SET Inv_Transfer_Date = **UpdateCommand WHERE Inv_Num IN ( SQL_Arr = SQL_Arr & iArr & ") "

标签: .net sql-server vb.net parameters in-clause


【解决方案1】:

SQL Server 现在可能支持为参数传递数组。许多 DB 没有,Microsoft Connect 上仍有一个未解决的请求。值得一试。

您还应该打开Option Strict。您的 SQL_Arr 被声明为字符串,但您为其分配了一个 XML 文字,然后将该文字作为命令文本传递。

这将创建一个 SQL 语句,其中 Id 列表中的每个项目都有自己的参数,然后是它为其设置的值。它使用 Id 的一些随机数据来模拟一个变化的列表,它使用 MySQL...概念将是相同的。

' test data: random set of IDs to update
Dim idList = Enumerable.Range(1, 2500).OrderBy(Function(r) RNG.Next()).Take(8).ToList()

Dim sql As String = <sql>
            UPDATE SampleX SET `Value`= @v WHERE Id IN (@theList)
          </sql>.Value

' create the parameter placeholders
' results in a list of "@pX" items where X is a number
Dim params = Enumerable.Range(1, idList.Count).
            Select(Function(q) String.Format("@q{0}", q)).
            ToList()

' join the list of parms to make '@q1, @q2...'
' then replace @thelist with that string
sql = sql.Replace("@theList", String.Join(",", params))

' run the query
Using dbcon As New MySqlConnection(MySQLConnStr)
    Using cmd As New MySqlCommand(sql, dbcon)

        ' specify the value
        cmd.Parameters.Add("@v", MySqlDbType.Int32).Value = -6

        ' loop to supply an Id value for each IN parameter
        ' placeholder created
        For n As Int32 = 0 To params.Count - 1
            cmd.Parameters.Add(params(n), MySqlDbType.Int32).Value = idList(n)
        Next

        dbcon.Open()
        Dim rows = cmd.ExecuteNonQuery()
    End Using

    ' debug/demo: show the results
    sql = "SELECT Name, Descr, Value, Country FROM SampleX WHERE Value=-6"
    Using cmd As New MySqlCommand(sql, dbcon)
        dtSample = New DataTable
        dtSample.Load(cmd.ExecuteReader())
        dgv1.DataSource = dtSample
    End Using
End Using

我们希望查询保持参数化,因此第一部分创建了一个 @q1 占位符列表 - 与要更新的 ID 一样多。在循环中创建占位符:

Dim params As New List(Of String)
For n As Int32 = 0 To idList.Count - 1
    params.Add(String.Format("@q{0}", (n + 1).ToString()))
Next

接下来,代码将 SQL 中的 @theList 替换为列表的连接版本。结果:

UPDATE SampleX SET `Value`= @v WHERE Id IN (@q1,@q2,@q3,@q4,@q5,@q6,@q7,@q8)

如果IN 子句处理的是字符串而不是整数,请在参数创建中添加刻度:String.Format("'@q{0}'",...

剩下的很简单:为每个参数指定 ID:

' params(n) e.g. "q1"  and idList(n) is the value e.g. 11111
cmd.Parameters.Add(params(n), MySqlDbType.Int32).Value = idList(n)

我的示例只是将 a 值设置为 -6 以便于查找。它有效:

最后,请注意生成的 SQL 允许的最大长度。该最大值取决于 DB Provider 并且非常大,但如果您的 IN 子句有很多 Id,您可能需要将其分成多个批次。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-02
    • 1970-01-01
    • 2010-12-17
    • 2016-08-10
    • 1970-01-01
    • 2016-04-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多