Эффективное обновление SQL, обновление нескольких строк одним оператором SQL, предотвращение циклов - PullRequest
1 голос
/ 09 января 2012

Я пытаюсь избежать доступа к базе данных в циклах в проекте, над которым я работаю. Не слишком хорошо разбираясь в SQL, я не уверен, что лучше всего подойти к этому.

Я обновляю базу данных уровня запасов в процедуре продажи с несколькими местоположениями складов / местами выбора.

Следовательно, это то, что я делаю.

Цикл по идентификаторам продуктов, затем цикл по пунктам выбора для каждого продукта и обновление количества по мере поступления, например:

For Each wProductId In calculatedProds.Keys '' loop through products requested passing values of pick locations
        For i = 0 To locationCount ' split the location value from the string as per above
            Dim thisLocation As Integer = locationID
            Dim thisQty As Integer = qtyPicked                
            Dim sql As String = "UPDATE `stockLevels` SET `stockLevel`=`stockLevel` - '" & thisQty & "' WHERE `stockLocation`='" & thisLocation & "' AND `id`='" & wProductId & "'"
            ' DO DATA ACCESS WITH SQL ABOVE       
        Next
Next

Конечно, это работает, но оно открывает новое соединение с базой данных для каждого склада, для каждого предмета.

Так, как бы я превратил это в один оператор обновления?

http://www.karlrixon.co.uk/writing/update-multiple-rows-with-different-values-and-a-single-sql-query/

Мне кажется, что эта ссылка очень приближает меня к тому, что мне нужно, но я не уверен на 100%, как динамически построить этот оператор SQL и как добавить два условия в CASE.

Мне нужно создать SQL-выражение, например:

UPDATE stockLevels
SET stockLevel= CASE id
    WHEN '"& wProductId  &"' AND stockLocation='"& thisLocation &"' THEN `stockLevel` - '" & thisQty & "'
    WHEN '"& NEXTwProductId  &"' AND stockLocation='"& NEXTthisLocation &"' THEN `stockLevel` - '" & NEXTthisQty & "'
END

Но это не правильно, когда я добавляю второй параметр в CASE!

Я использую MySQL и VB.NET, как обычно, любая помощь очень ценится.

Ответы [ 2 ]

5 голосов
/ 09 января 2012

Использование оператора case в предложении set в вашем примере не идеально по ряду причин.

  • Нет условия where, чтобы помочь базе данных эффективно выполнить запрос
  • Размер запроса для большого количества обновлений становится чрезмерным (рассмотрите возможность обновления 1000 строк следующим образом)
  • Вы выполняете объединение вручную - база данных почти наверняка может сделать это более эффективно, чем вы.
  • Отладка такого запроса также сложна.

Вместо этого вы должны сначала измерить производительность обновления по одному, чтобы увидеть, действительно ли вам нужно вносить улучшения.

Если требуется повышение производительности, я бы предложил подход, при котором обновления сначала массово вставляются во временную таблицу. Подходящая таблица будет иметь следующие столбцы:

wProductID, stockLocation, newStockLevel

Обновления могут быть массово вставлены с использованием следующего синтаксиса MySQL:

INSERT INTO temp_stock_updates
    (wProductID, stockLocation, newStockLevel)
VALUES
    (?,?,?), (?,?,?), (?,?,?), ...

А затем запускается одно обновление для обновления основной таблицы. Этот запрос будет выглядеть примерно так:

UPDATE stockLevels s
    JOIN temp_stock_updates u USING (wProductID, stockLocation)
SET
    s.stockLevel = u.newStockLevel
1 голос
/ 09 января 2012

Ваше CASE-выражение просто неверно синтаксически.

Существует два вида CASE выражений, почти идентичных друг другу, но немного отличающихся по синтаксису.

Одно имеет форму

CASE expr
  WHEN value1 THEN result1
  WHEN value2 THEN result2
  ...
  ELSE result_else
END

Другой выглядит так:

CASE
  WHEN condition1 THEN result1
  WHEN condition2 THEN result2
  ...
  ELSE result_else
END

И вы, по сути, пытались смешать эти два вида CASE.

Возможно, вам просто нужноиспользуйте второй (также называемый search CASE , если я не сильно ошибаюсь):

...
CASE
  WHEN id = '"& wProductId  &"' AND stockLocation='"& thisLocation &"' THEN ...
  WHEN id = '"& NEXTwProductId  &"' AND stockLocation='"& NEXTthisLocation &"' THEN ...
...

Обратите внимание, что если совпадения нет, а CASE не имеет ELSE частирезультат будет NULL, поэтому убедитесь, что вы охватили все случаи, в противном случае используйте ELSE часть, подобную этой:

ELSE `stocklevel`

Т.е. CASE будет соответствовать исходному значениюстолбца, который обновляется, в конце концов не обновляется для него.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...