使用遊標(Cursors)將多行查詢結果逐行處理

在SYBASE數據庫中,說明性數據庫語言(SQL)是目前首推的最成功,應用最廣泛的數據庫語言,它已成爲關係型數據庫語言的國際標準。這主要得益於它的兩大優點:一是免除了用戶描述操作過程的麻煩,而將其轉嫁給系統,系統可根據用戶所提出的要求,確定一個有效的操作過程,二是其語言本身接近英語的自然語言,易學易用,很受用戶歡迎。儘管如此,SQL語言一般侷限於對數據庫的操作,本身不是計算完備的語言,如在變量類型上不像高級程序設計語言(如:C語言)有如數組、指針等一些複雜變量類型;另外該語言是面向集合的語言(set_oriented languase),即執行一條語句可以一次性地提供所需的所有元組,可是在實際編程時我們需要對這些元組逐個地賦值給相關變量,根據條件分別處理。目前解決此類問題辦法是將SQL語言嵌入到高級程序設計語言中,利用高級程序設計語言處理數據能力強的優點,與SQL語言對數據庫直接操作的特點相結合,共同完成,這在一定程度上,既增加編寫程序的難度,又使整個程序繁瑣。下面我向大家介紹在新版SYBASE數據庫中,增加的工具遊標,使用它可以方便地實現將多行查詢結果進行逐行處理。 

一、首先介紹遊標的功能、相應的操作命令、變量及工作流程 

  遊標(cursor)主要功能是用select查詢語句,得到的多行數據結果,一次一行地送至需要調用的存儲過程或宿主程序中,最初遊標指向第一行數據,將這行數據送至存儲過程或宿主程序中,然後遊標又指向下一行數據,這樣一直循環下去,直至所有的數據全部調用完畢,它可以方便靈活地修改或刪除遊標所在行的數據。 

遊標的機制由以下五條語句及兩個全局變量來完成。 

1、說明語句。對一個遊標進行命名,並將它與相應的查詢語句相聯繫。 

語法是:declare cursor_name cursor for select_statement 

其中:select_statement是一個SELECT語句,這個語句返回多行結果數據,它不允許有INTO子句和COMPUTE子句存在。 

2、打開遊標語句。執行與遊標相聯繫SQL查詢語句,並將查詢結果置於遊標中。 

語法是:open cursor_name 

3、取數語句。用來從打開的遊標中檢索數據,並將這些數據賦給宿主變量。在每次執行取數語句時,首先將遊標向前推進一位,然後按照遊標當前位置取一值,並對相應變量賦值。 

語法是:fetch cursor_name int host_ vavriable,…… 

4、關閉遊標語句。當取數完畢或者發生錯誤時,一定要關閉遊標。否則下次調用遊標將出錯。 

語法是:close cursor_name 

5、 刪除遊標語句,該語句主要是將遊標調用的內存資源釋放。 

語法是:dellocate cursor_name 

全局變量:@@rowcount;使用取數語句返回行值數。 

@@sql status 取數返回狀態變量,值有三個: 

0表示取數成功。 

1表示取數結果錯誤。 

2表示沒有可取的數。 

遊標的工作流程圖如下: 
二、接下來這個程序是我運用遊標功能,編寫的計算定期存款應付利息的程序。 

程序由兩個存儲過程組成,需要調用定期存款表(t_dqcd)和利率表(t_ll)的數據,由於每筆存款金額、存期、適用利率、開戶日不同,在進行計算定期存款應付利息時,只能按戶逐筆進行。 

第一個存儲過程主要是執行遊標操作語句,提出輸入參數“帳號”,並調用存儲過程“單帳號應付利息”,得出輸出參數“單帳戶利息值”,並對其進行累加,直到算出所有帳戶的應付利息。 

具體程序如下: 

print 'install yflx.....' 

go 

drop proc yflx 

go 

create proc yflx 

@we money output 

as 

declare c1 cursor for /*說明遊標C1 */ 

select wh from t_dqcd where zhzt <> '1' 

declare @iwh char(9) 

declare @wh char(9) 

declare @hzs char(12) 

declare @ff money 

declare @jj money 

open c1 /*打開遊標*/ 

select @jj = 0.00 /*賦初值爲0*/ 

fetch c1 into @iwh /*提出遊標數據給變量*/ 

while @@sqlstatus != 2 

begin 

if @@sqlstatus =1 

begin 

   raiserror 20001 "select fail" 

return 

end   

exec dhlx @wh=@iwh,@dhlx=@ff output /*調動存儲過程*/ 

select @jj = @jj + @ff 

fetch c1 into @iwh 

end 

select @we = @jj/*將彙總數付給輸出變量*/ 

close c1/*關閉遊標*/ 

deallocate cursor c1/*刪除遊標*/ 

go 

第二個存儲過程主要根據遊標所提取的帳號運用sql查詢語句,算出實際存期和當時掛牌利率,最終算出該帳戶的應付利息。 

計算公式爲: 

未到期定期儲蓄存款 

應付利息=本金×實際天數×存入時掛牌利率 

逾期定期儲蓄存款 

應付利息=本金×存期×存入入時掛牌利率+本金×逾期天數×現行活期掛牌利率 

具體程序如下: 

print 'install dhlx .....' 

go 

drop proc dhlx 

go 

create proc dhlx 

@wh char(9), 

@dhlx money output 

as 

declare @ts smallint 

declare @yflx money 

declare @cts char(9) 

declare @hqll float 

declare @bcc char(5) 

declare @zhbcc char(2) 

declare @sbcc smallint 

declare @khrq smallint 

select @bcc=bcc from t_dqcd where wh=@wh 

select @zhbcc=substring(@bcc,3,2) 

select @sbcc= convert(int,@zhbcc) 

select @ts=(datediff(mm,(select qxr from t_dqcd where wh =@wh),getdate())*30 + datepart(dd,getdate()) - datepart(dd, (select qxr from t_dqcd where wh=@wh))) from t_dqcd where wh=@wh /*計算實際存取天數*/ 

select @cts = convert(char, @ts) 

select @hqll=ll from t_ll where bcc='12000' and rq=(select max(rq) from t_ll) 

if @ts < @sbcc*30  /*檢查該存款是否到期*/ 

select @yflx=round(((select bjje from t_dqcd where wh=@wh)*(select ll from t_ll where bcc=(select bcc from t_dqcd where wh=@wh)and rq=(select max(rq) from t_ll where bcc=(select bcc from t_dqcd where wh =@wh) and rq !> (select khr from t_dqcd where wh=@wh)))*(datediff(mm,(select qxr from t_dqcd where wh 

=@wh),getdate())*30 + datepart(dd,getdate()) - datepart(dd,(select qxr from t_dqcd where wh=@wh)))/30000),2) from t_dqcd where wh=@wh 

else 

select @yflx=round((((select bjje from t_dqcd where wh=@wh)*(select ll from t_ll where bcc=(select bcc from t_dqcd where wh=@wh)and rq=(select max(rq) from t_ll where bcc=(select bcc from t_dqcd where wh =@wh) and rq !> (select qxr from t_dqcd where wh=@wh)))*@sbcc)/1000+((select bjje from t_dqcd where wh=@wh)*@hqll*(@ts-@sbcc*30))/30000),2) from t_dqcd where wh=@wh 

select @dhlx=@yflx 

go 

總結:由於在程序中用遊標對多行查詢結果進行逐行處理,保證了使用SYBASE數據庫查詢語句進行子查詢時返回值唯一,使整個程序結構簡練、條理清晰。 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章