2012-01-11 63 views
17

是否可以向SQL Update語句添加TOP或某種分頁?如何在批處理中執行SQL UPDATE,如更新頂端?

我有一個UPDATE查詢,這可以歸結爲這樣的事:

UPDATE XXX SET XXX.YYY = #TempTable.ZZZ 
FROM XXX 
INNER JOIN (SELECT SomeFields ...) #TempTable ON XXX.SomeId=#TempTable.SomeId 
WHERE SomeConditions 

此更新將影響到數以百萬計的記錄,我需要做的是在批次。在當時像100.000(訂購無關緊要)

要做到這一點最簡單的方法是什麼?

回答

17

是的,我相信你可以在更新語句中使用TOP,像這樣:

UPDATE TOP (10000) XXX SET XXX.YYY = #TempTable.ZZZ 
FROM XXX 
INNER JOIN (SELECT SomeFields ...) #TempTable ON XXX.SomeId=#TempTable.SomeId 
WHERE SomeConditions 
+8

'TOP'由什麼作爲排序?第二批在第一批完成的地方如何選擇? – 2012-01-11 14:06:27

+0

一種可能性是在更新記錄每個記錄時,然後添加另一個子句,忽略已更新的記錄。這需要臨時向表中添加一列(除非有一些有效的方式來判斷記錄是否因爲更新本身而被更新)。 – ean5533 2012-01-11 14:08:23

+0

Eh oke很簡單..我使用UPDATE TOP 100000進行了測試,但是這給出了'100000附近的錯誤語法',更新TOP(100000)似乎工作。 @MartinSmith:在我的情況下,「第二批」並不重要。當第一批更新時,它將不再符合條件。 – 2012-01-11 14:09:29

3

根據您改變表的數據結構的能力,我建議你一個字段添加到您的表可以容納某種批次標識符。 IE瀏覽器。它可以是一個日期標記,如果你每天都做它,增量值或基本上任何值,你可以使你的批次獨一無二。如果採取漸進式方法,您的更新將爲:

UPDATE TOP (100000) XXX SET XXX.BATCHID = 1, XXX.YYY = .... 
... 
WHERE XXX.BATCHID < 1 
    AND (rest of WHERE-clause here). 

下一次,你將設置BATCHID = 2和WHERE XXX.BATCHID < 2

如果這是要反覆做,可以設置索引在BATCHID上並減少服務器上的負載。

5

您可以使用SET ROWCOUNT { number | @number_var }它限制在停止特定查詢之前處理的行數,下面的例子:

SET ROWCOUNT 10000 -- define maximum updated rows at once 

UPDATE XXX SET 
    XXX.YYY = #TempTable.ZZZ 
FROM XXX 
INNER JOIN (SELECT SomeFields ...) #TempTable ON XXX.SomeId = #TempTable.SomeId 
WHERE XXX.YYY <> #TempTable.ZZZ and OtherConditions 

-- don't forget about bellow 
-- after everything is updated 
SET ROWCOUNT 0 

我已經添加到XXX.YYY <> #TempTable.ZZZ條款where,以確保您不會更新已經兩次更新值。

設置ROWCOUNT0關閉限制 - 不要忘記它

+0

也是一個很好的工作答案,但我只能接受一個答案。另一個答案是最短和最快的方式來做我想做的事。 – 2012-01-12 10:17:20

+2

SET ROWCOUNT已被限制用於限制UPDATE,INSERT和DELETE語句。從SQL 2005開始,應該使用TOP。 – Jim 2013-07-11 13:12:59

+0

以上評論有幫助;這裏有一些支持:https://sqlstudies.com/2013/10/07/use-top-instead-of-set-rowcount/ – jacoblambert 2016-10-05 13:30:12

2

你可以不喜歡以下

declare @i int = 1 
while @i <= 10 begin 

    UPDATE top (10) percent 
      masterTable set colToUpdate = lt.valCol 
    from masterTable as mt 
      inner join lookupTable as lt 
        on mt.colKey = lt.colKey 
    where colToUpdate is null 

    print @i 
    set @i += 1 
end 

--one final update without TOP (assuming lookupTable.valCol is mostly not null) 
UPDATE --top (10) percent 
     masterTable set colToUpdate = lt.valCol 
from masterTable as mt 
     inner join lookupTable as lt 
       on mt.colKey = lt.colKey    
where colToUpdate is null