2011-12-12 39 views
2

我想更新光標內的一行。我正在嘗試的是使用OLD_QTY和NEW_QTY更新記錄鏈。但是,當我嘗試執行更新時,即使在我的declration中包含了for update of OLD_QTY, NEW_QTY,也會給出錯誤The cursor is READ ONLY。如果我在select語句中包含OLD_QTYNEW_QTY,則沒有區別。光標說它的只讀,即使我宣佈它「更新」

declare @current_inv_guid uniqueidentifier 
declare @last_inv_guid uniqueidentifier 
declare @current_vid int 
declare @last_vid int 
--declare @current_new_qty money 
declare @last_new_qty money 
--declare @current_old_qty money 

declare iaCursor cursor 
     for select INV_GUID, old_VID 
      --, OLD_QTY, NEW_QTY 
      from #IA 
      order by INV_GUID, old_vid, ENTRY_NUM 
     for update --of OLD_QTY, NEW_QTY 
open iaCursor 
Fetch next from iaCursor into @current_inv_guid, @current_vid --, @current_old_qty, @current_new_qty 

while @@fetch_status = 0 
begin 
    --test to see if we hit a new chain. 
    if(@last_inv_guid <> @current_inv_guid or @current_vid <> @last_vid) 
    begin 
     set @last_new_QTY = (select #lots.QTY_RECEIVED from #lots where #lots.INV_GUID = @current_inv_guid and LOT_VID = @current_vid) 
     set @last_inv_guid = @current_inv_guid 
     set @last_vid = @current_vid  
    end 

    --update the current link in the chain 
    update #ia 
     set OLD_QTY = @last_new_QTY, 
      NEW_QTY = @last_new_QTY + QTY_CHANGE, 
      @last_new_QTY = @last_new_QTY + QTY_CHANGE 
     where current of iaCursor 

    --get the next link 
    fetch next from iaCursor into @current_inv_guid, @current_vid --, @current_old_qty, @current_new_qty 
end 

close iaCursor 
deallocate iaCursor 
+0

相關:http://stackoverflow.com/questions/14172501/why-an-cursor-opened-for-a-select-with-order-by-does-not-reflect-updates-to-the – bummi

回答

2

而且你在回答中提到的原因,你正在做的事與SQL意味着要使用的方式背道而馳。嘗試更新集合中的數據,而不是行。

我不是積極,因爲我不知道你的餐桌設計,但我相信下面應該工作。你可能得到更好的表現。特別是,我假設QTY_CHANGE來自#ia,雖然可能並非如此。

UPDATE #ia as a set (OLD_QTY, NEW_QTY) = (SELECT #lots.QTY_RECEIVED + (COUNT(b.*) * a.QTY_CHANGE), 
               #lots.QTY_RECEIVED + ((COUNT(b.*) + 1) * a.QTY_CHANGE) 
              FROM #lots 
              LEFT JOIN #ia as b 
              ON b.INV_GUID = a.INV_GUID 
              AND b.OLD_VID = a.OLD_VID 
              AND b.ENTRY_NUM < a.ENTRY_NUM 
              WHERE #lots.INV_GUID = a.INV_GUID 
              AND #lots.LOT_VID = a.OLD_VID) 
WHERE EXISTS (SELECT '1' 
       FROM #lots 
       WHERE #lots.INV_GUID = a.INV_GUID 
       AND #lots.LOT_VID = a.OLD_VID) 


編輯:

...答案以前版本用DB2角度來寫的,儘管它本來是DB-無關。它也存在每行使用相同值QTY_CHANGE的問題,這是不太可能的。這應該是一個更地道的SQL Server 2008版本,以及更可能輸出正確答案:

WITH RT AS (SELECT #IA.inv_guid, #IA.old_vid, #IA.entry_num, 
        COALESCE(MAX(#Lots.qty_received), 0) + 
         SUM(#IA.qty_change) OVER(PARTITION BY #IA.inv_guid, #IA.old_vid 
                ORDER BY #IA.entry_num) 
         AS running_total          
         FROM #IA 
         LEFT JOIN #Lots 
           ON #Lots.inv_guid = #IA.inv_guid 
           AND #Lots.lot_vid = #IA.old_vid) 
UPDATE #IA 
SET #IA.old_qty = RT.running_total - #IA.qty_change, #IA.new_qty = RT.running_total 
FROM #IA 
JOIN RT 
    ON RT.inv_guid = #IA.inv_guid 
    AND RT.old_vid = #IA.old_vid 
    AND RT.entry_num = #IA.entry_num 
6

把在select一個order by取得的光標只讀。

+0

This答案有點誤導,所以我貼了我自己的。 – GSerg

5

您不明確說明您想要什麼行爲,因此default rules適用,根據該行爲,根據底層查詢,遊標可能可以更新也可能不可更新。

這是完全正常的可更新的遊標使用order by,但你必須得更加詳細,並告訴SQL Server,則在細節想要的東西,比如:

declare iaCursor cursor 
local 
forward_only 
keyset 
scroll_locks 
for 
    select INV_GUID, old_VID 
    from #IA 
    order by INV_GUID, old_vid, ENTRY_NUM 
for update of OLD_QTY, NEW_QTY 
0

一些遊標聲明不允許更新。該documentation給出瞭如下評論暗示:

  • 如果SELECT語句不支持更新(權限不夠,訪問不支持更新,並 等遠程表),遊標是READ_ONLY。

我試圖加入一個觸發的「插入」對象遊標聲明的SELECT語句時碰到了同樣的問題。

2

有進口,但微妙的音符documentation頁帕特里克上市:

如果查詢至少引用一個表沒有唯一索引, 鍵集遊標將轉換爲靜態遊標。

當然,STATIC遊標是隻讀的。

相關問題