CREATE PROCEDURE [c_readtop] @eachrow int=10 AS
declare @tmpcat varchar(16)
create table #tmp_result (arid int,cat2 varchar(16),title varchar(100),upday datetime)
declare rt_cursor cursor
for select cat2 from category where cat1='電腦手冊' and catl=2
open rt_cursor
fetch from rt_cursor into @tmpcat
while @@fetch_status=0
Begin
set rowcount @eachrow
Insert into #tmp_result (arid,cat2,title,upday) Select top 10 arid,cat2,title,upday from article as a
left join category as b on a.sortid=b.catid where b.cat1='電腦手冊' and b.cat2=@tmpcat order by upday desc
fetch from rt_cursor into @tmpcat
End
select * from #tmp_result
drop table #tmp_result
close rt_cursor
deallocate rt_cursor
此存儲過程的作用是取出每個分類的最新10條記錄。
出現的錯誤信息是(一旦操作返回的記錄集時就出現):
ADODB.Recordset 錯誤 '800a0e78'
The operation requested by the application is not allowed if the object is closed.
此存儲過程能在qa中正常運行且能得到正確結果,使用odbc連接數據庫的話,也能得到正確的結果。于是首先懷疑oledb方
式連接沒能返回記錄集。進行了下面的調試:
(一)加調試標記,在調用記錄集前用set rs=rs.nextrecordset測試是不是命中返回的記錄集……
(二)由于該過存原來是另一個過程的一部分,懷疑存儲過程中有些語句不能同時使用,于是將該過程分離成一個獨立的
存儲過程,錯誤依舊。
(三)懷疑調用該過程的Asp有問題,于是重做一個只是調用該存儲過程的Asp程序,錯誤依舊。
(四)將連接方式改為odbc方式連接(建dsn,設sql server的login ID,設權限),該錯誤消失。重新使用oledb連接,
錯誤依舊。
(五)懷疑對臨時表的數據插入有問題,取消去臨時表插入數據,能返回一個空的記錄集。
(六)經Bigeagle提示,將臨時表建在臨時數據庫tempdb上,錯誤依舊
(七)把存儲過程中的drop table去掉,在qa中運行該存儲過程,觀察臨時表的生成情況,發現臨時表正確生成且有正確
的數據插入,百思不得其解,數據輸出到哪了?
(八)經Bigeagle提示create table一句返回了記錄集,于是重新在輸出記錄集前使用多個set rs=rs.nextrecordset(最
多放上了4個),錯誤提示依舊。
(九)懷疑臨時表操作有問題,將臨時表改為固定表,不插入數據時返回空記錄集,插入記錄時仍然提示錯誤。在記錄集
輸出前先執行一個或多個set rs=rs.nextrecordset,終于有一次沒有提示出錯(檢測到rs.eof為false),于是才恍然大
悟——不但是create table返回了記錄集,而且連insert into語句也返回了記錄集,不過該記錄集得一種特別的記錄集
(沒有字段,不能對該記錄集進行任何操作——連檢測rs.eof都不允許),我在此將它稱為特殊的記錄集,方便下面引
用。
(十)知道了問題的癥結,就馬上解決了,在存儲過程中不希望返回記錄集前執行set nocount on,要返回記錄集時,先
執行set nocount off。
也就是改成:
CREATE PROCEDURE [c_readtop] @eachrow int=10 AS
declare @tmpcat varchar(16)
set nocount on
create table #tmp_result (arid int,cat2 varchar(16),title varchar(100),upday datetime)
declare rt_cursor cursor
for select cat2 from category where cat1='電腦手冊' and catl=2
open rt_cursor
fetch from rt_cursor into @tmpcat
while @@fetch_status=0
Begin
set rowcount @eachrow
Insert into #tmp_result (arid,cat2,title,upday) Select top 10 arid,cat2,title,upday from article as a
left join category as b on a.sortid=b.catid where b.cat1='電腦手冊' and b.cat2=@tmpcat order by upday desc
fetch from rt_cursor into @tmpcat
End
set nocount off
select * from #tmp_result
drop table #tmp_result
close rt_cursor
deallocate rt_cursor
問題解決。
在該存儲過程調試過程中,發現oledb和odbc存在一個很大的差別,asp向odbc取記錄集時,odbc過濾了上面所稱的特
殊記錄集(那種只占位置但不能進行任何操作的記錄集——多由create table或insert into產生),而asp向oledb取記錄
集時,oledb并沒有將特殊記錄集過濾。
同時,認識到在使用存儲過程返回記錄集時,在不希望返回記錄的地方,應該使用set nocount on禁止存儲過程返回
記錄集,否則可能會繞很多彎路。
終于明白了為什么繞了這么多彎路:沒有想到oledb返回了這么多特殊的記錄集(還是由一個循環產生的,該循環執行
次數5、6次),怪不得在取記錄集前雖然執行了set rs=rs.nextrecordset,但終因數據不夠多而未能發現錯誤癥結所在。
特別感謝在調試過程中bigeagle給予的提示,多謝。