2016-09-05 8 views
2

Я пытаюсь обновить, используя предложение IN, однако я не могу заставить его работать. Мой iArr создает список чисел, разделенных запятой, и теоретически, как только он заключен в скобки, он должен обновиться, но он не работает. Я продолжаю получать сообщение об ошибкеЗапрос SQL Server с использованием параметров для IN-раздела

Конверсия не удалась при преобразовании значения nvarchar '111111, 222222, 333333' в datatype 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() 
+0

Это не ответ, но вы должны, вероятно, параметризовать предложение 'WHERE'. Я думаю, что форсунки SQL будут вспениваться во рту с тем, что у вас есть. –

+0

Сначала проверьте, будет ли этот провайдер принимать массивы для параметров. Мне всегда приходилось форматировать и расширять их. – Plutonix

+0

Попробуйте изменить свой массив из '('item1, item2')' to '('item1', 'item2')' –

ответ

1

Вполне возможно, что SQL Server теперь поддерживает передачу массивов параметров. У многих БД нет, и по-прежнему есть открытый запрос для этого на Microsoft Connect. Было бы полезно выяснить.

Вы также должны включить Option Strict. Ваш SQL_Arr объявлен как строка, но вы присваиваете ему литерал XML, а затем передаете этот литерал как текст команды.

Это создаст инструкцию SQL, в которой каждому элементу в списке идентификаторов присваивается свой собственный параметр, а затем значение, которое оно задает для него. Он использует некоторые случайные данные для идентификаторов для эмуляции различного списка и использует 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 заполнителей - как многие из них, как есть Идентификаторы обновить. Чтобы создать заполнители в цикле:

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 

Далее, код заменяет @theList в SQL с объединенной версией списка. Результат:

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

Если условие IN имеет дело со строками, а не целые числа, добавить тиков к созданию параметров: String.Format("'@q{0}'",...

Остальное прямо вперед: указать идентификатор для каждого параметра:

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

Мой образец просто установил значение -6, чтобы их было легко найти. Он работает:

enter image description here

Наконец, обратите внимание, что максимальная допустимая длина результирующей SQL. Этот макс зависит от поставщика БД и довольно большой, но если в вашем предложении IN имеется большое количество идентификаторов, вы можете разбить его на партии.

 Смежные вопросы

  • Нет связанных вопросов^_^