2011-12-12 33 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游标是只读的。

相关问题