日期:2014-05-18  浏览次数:20681 次

SQL SERVER游标问题-所请求的行不在提取缓冲区内
请帮我看看下面的游标有什么问题:
说明:tab表中有字段ID,adress.现在要重新编排ID,adress列相同的记录共用同一个ID.第一条记录的ID已经确定为1,往后依次递增.

declare cur_tab cursor scroll for  
select ID,address from tab
declare @xuhao1 varchar(15),@xuhao2 varchar(15),@addr1 varchar(15),@addr2 varchar(15)
open cur_tab
fetch next from cur_tab into @xuhao1,@addr1
while @@fetch_status=0
begin  
  fetch next from cur_tab into @xuhao2,@addr2
  if @addr1=@addr2
  update tab set ID=@xuhao1 where current of cur_tab
  else 
  update tab set ID=@xuhao1+1 where current of cur_tab
  set @xuhao1=@xuhao2
  set @addr1=@addr2
end
close cur_tab  
deallocate cur_tab  


执行结果有这样的提示:

执行结果报错:
服务器: 消息 16930,级别 16,状态 1,行 10
所请求的行不在提取缓冲区内。
语句已终止。

查看结果,发现只增加了一个新的ID.这样看来是没有正常循环,但是又找不到哪里有毛病,哪位帮我看看,谢谢!


------解决方案--------------------
READ ONLY

禁止通过该游标进行更新。在 UPDATE 或 DELETE 语句的 WHERE CURRENT OF 子句中不能引用游标。该选项优于要更新的游标的默认功能。

------解决方案--------------------
lz 的算法有问题。
fetch next 是提取当前位置的数据后,再向后移动一行。因此,在 fetch next 提取最后一行数据后,游标的位置将不再是有效位置,update 当然会无效。

最关键的在于此算法无法实现 lz 的要求。如果 select ID,address from tab 的结果集不是按 address 列排序,即相同的 address 列值不相邻,游标将无法为 address 列相同的记录分配相同的 id 值。另外,fetch next 后,update 更新不是当前行的数据,而是下一行的数据。

其实,可以直接用 update 语句就可以直接更新,
;with cte as(
select id,dr=DENSE_RANK() over (order by address) from tab
)
update tab set tab.id=cte.dr from tab,cte where tb.id=cte.id;


------解决方案--------------------
觉得这类问题还是不用游标,将键值提取来放到一个内存表中做循环比较好.