各位同仁,偶遇到大麻烦了.

存储过程中使用了动态游标,程序片断如下
exec('declare cur cursor for select * from table '+ @where);
open cur;
fetch next from cur into @v1,@v2
语法上没什么问题,原来也都是运行正常,正在进行功能测试着呢。突然从昨天看是提示:
服务器: 消息 16916,级别 16,状态 1,过程 Query,行 231
A cursor with the name 'cur' does not exist.
什么原因导致的?
[320 byte] By [badtank-爱与宿命的连发枪] at [2008-6-5]
# 1
估计没有比重建更好的方法了?
larson-Unkonwn at 2007-10-20 > top of Msdn China Tech,MS-SQL Server,基础类...
# 2
是不是其他地方的错误,比如游标关闭后再使用的。
你确定行 231就是在这一段吗?

Yang_-扬帆破浪 at 2007-10-20 > top of Msdn China Tech,MS-SQL Server,基础类...
# 3
@where变量的值可能有问题!
造成exec语句执行失败,动态定义光标失败。
因此server上会报这个错误。

请仔细检测你的@where变量,将其打印出来看看是否是标准的。
IronPromises-铁诺 at 2007-10-20 > top of Msdn China Tech,MS-SQL Server,基础类...
# 4
cur写在字符串中,用open可以吗?

exec('declare cur cursor for select * from table '+ @where);
exec('open cur');
exec('fetch next from cur into '+@v1'+','+@v2)
试试

mophi-追球 at 2007-10-20 > top of Msdn China Tech,MS-SQL Server,基础类...
# 5
铁斑竹说的可能性最大!
Yang_-扬帆破浪 at 2007-10-20 > top of Msdn China Tech,MS-SQL Server,基础类...
# 6
IronPromises(铁诺) 说的最有可能
gzhughie-hughie at 2007-10-20 > top of Msdn China Tech,MS-SQL Server,基础类...
# 7
对..
同意..
应该是条件子句有问题..
# 8
exec('declare cur cursor for select * from table '+ @where)中的表名叫table吗?
declare str varchar(200)
str='declare cur cursor for select * from table '+ @where
select str
看看输出的结果是否合理
# 9
单步跟踪,看条件语句是否正确!根据你说的,也只能给出此结论了!
zou5655-周围 at 2007-10-20 > top of Msdn China Tech,MS-SQL Server,基础类...
# 10
不瞒你说,我在一年前的这个时候首次使用动态光标的时候就出现过这种问题。
我有一个表TransMaster,里面有个varchar型的字段COMP_ID,这个字段有可能存放’001’之类的全数字varchar型字符,也有可能存放’ABC’之类的有字母的varchar型字符。

那么我如果我这样写的静态SQL的话:
declare @comp_id varchar(3)
set @comp_id = '001'
select TRANS_NO from TransMaster where COMP_ID = @comp_id
或者
declare @comp_id varchar(3)
set @comp_id = 'ABC'
select TRANS_NO from TransMaster where COMP_ID = @comp_id
怎么样都不会报错。

但是我如果要改成动态光标性质的话:
declare @comp_id varchar(3),@SQL varchar(4000)
set @comp_id = '001'
set @SQL = 'select TRANS_NO from TransMaster where COMP_ID = '+ @comp_id
exec ('declare cur cursor for '+@SQL)
open cur
……
这样也不会报错。但是我要是把第二句set @comp_id = '001'改成set @comp_id = 'ABC'的话就会报出和你现在一模一样的错误,说光标cur不存在!
后来我知道了原因,就引入了QUOTENAME函数,将第三句
set @SQL = 'select TRANS_NO from TransMaster where COMP_ID = '+ @comp_id
改成了:
set @SQL = 'select TRANS_NO from TransMaster where COMP_ID = '+QUOTENAME(@comp_id,'''')
然后无论什么情况都不会出错了。

至于为什么会这样,我想海阔天空兄和一剑飘香兄等人肯定都知道。
如果你现在不知道,那么也不要紧,经验总是要慢慢积累的嘛!

像上面很多人写的单步跟踪什么的就不要去管他们了,简直是浪费时间!
你只要你的@where这个变量print出来告诉我,然后将你的table的字段类型告诉我就OK了。我帮你搞定。
IronPromises-铁诺 at 2007-10-20 > top of Msdn China Tech,MS-SQL Server,基础类...
# 11
其实关键的原因就在于:
如果TransMaster表的COMP_ID是字符型的话
select TRANS_NO from TransMaster where COMP_ID = 001
这条语句不会出错,只是找不到纪录。因为有个隐式转换在里面。

select TRANS_NO from TransMaster where COMP_ID = ABC
这条语句就会报错。

IronPromises-铁诺 at 2007-10-20 > top of Msdn China Tech,MS-SQL Server,基础类...
# 12
我覺得原因可能有三個。
1、鐵斑竹說的
2、有可能default to local cursor 的默認值發生了改變。在不指定local/global的情況下,默認是global的。2000下可用
SELECT DATABASEPROPERTYEX('northwind','IsLocalCursorsDefault')去查是否為1。 也可用EXEC sp_dboption去查default to local cursor 的值是否為true.
3、由於是global 的,所以其它進程可能已經關掉這個cursor了,所以沒辦法看見。

N_chow-Yukon at 2007-10-20 > top of Msdn China Tech,MS-SQL Server,基础类...
# 13
呀,我忽略了飘香的第3点。
光标的缺省值是global的。
有可能其它的session将其关闭了。
IronPromises-铁诺 at 2007-10-20 > top of Msdn China Tech,MS-SQL Server,基础类...
# 14
感谢大家的回复,其实在从这里提出问题之前,我就已经尝试了其中几位说的原因,甚至差点想着如larson(Unkonwn) 所说重新建库了。嗬嗬,实在是太麻烦,所以实在是不甘心。
实际的原因就是where条件语句。这个where语句也是根据条件动态生成的。我在字符串相加的时候没有判断null的情况,所以导致的这个原因 :(
铁斑竹说的最有代表性,SQL server的默认转换确实存在,尤其是数字的时候fieldname='001' 与 fieldname=001 是完全等价的。但是换了字符就出错了,如果不加单引号会提示找不到字段名的 :) 这个我也遇到过,处理的时候也考虑到了。
一剑飘香所说的游标默认值发生了改变,甚至是被其他的session给处理掉了。这个原因更加隐蔽,也不容易被发现。
扬帆破浪说的原因我觉得可以认为是SQL server作为存储过程编辑器的bug了。就是有个原因,错误位置定位不准确。
最后,感谢大家的热情帮忙。