建站服務(wù)器
引言
我們先不講游標(biāo)的什么概念,步驟及語法,先來看一個例子:
表一 originsalary 表二 addsalary
現(xiàn)在有2張表,一張是originsalary表–工資表,有三個字段0_id 員工號(nvarchar)、o_name員工姓名(nvarchar)、o_salary工資(float)。
另一張表addsalary表—加薪表。有2個字段,o_id員工號、a_salary增加工資。兩張表的o_id是一一對應(yīng)的,現(xiàn)在求將加薪的工資 原來的工資=現(xiàn)在的工資,也就是o_salary=o_salary a_salary,修改表originsalary的工資字段。
對于一些不熟悉游標(biāo)的程序員來說,這個并不是什么很難的問題,這個問題用程序來實現(xiàn)可能也很簡單。我先說說,用asp.net程序解決這個問題的思路:
1. 先獲得表originsalary的記錄數(shù),寫個循環(huán)。
2. 寫sql語句“select * from dbo.originsalary as a left join dbo.addsalary as b on a.o_id=b.o_id”獲得視圖。
3. 使用dataset獲得o_salary=o_salary a_salary。
4. 寫update語句“update originsalary set o_salary=”相加的值” where o_id=”獲得值”
5. 循環(huán)3次,完成此功能。
還有一種方法就是寫存儲過程,在這里我就不列出來了。
我想大家在學(xué)習(xí)游標(biāo)之前好好想想這個問題,及一些批量處理的例子。可能有的人會說:“難道數(shù)據(jù)庫不能一行一行的處理數(shù)據(jù)嗎?將表addsalary的數(shù)據(jù)逐行的取出,然后表 originsalary數(shù)據(jù)逐行的修改?”答案當(dāng)然是肯定。這就是游標(biāo)概念。接下來的一章我們會好好的講講什么是游標(biāo)?我會用游標(biāo)來解決剛才留給大家的問題。
1.1游標(biāo)的概念
游標(biāo)(cursor)它使用戶可逐行訪問由sql server返回的結(jié)果集。使用游標(biāo)(cursor)的一個主要的原因就是把集合操作轉(zhuǎn)換成單個記錄處理方式。用sql語言從數(shù)據(jù)庫中檢索數(shù)據(jù)后,結(jié)果放在內(nèi)存的一塊區(qū)域中,且結(jié)果往往是一個含有多個記錄的集合。游標(biāo)機制允許用戶在sql server內(nèi)逐行地訪問這些記錄,按照用戶自己的意愿來顯示和處理這些記錄。
1.2 游標(biāo)的優(yōu)點
從游標(biāo)定義可以得到游標(biāo)的如下優(yōu)點,這些優(yōu)點使游標(biāo)在實際應(yīng)用中發(fā)揮了重要作用:
1)允許程序?qū)τ刹樵冋Z句select返回的行集合中的每一行執(zhí)行相同或不同的操作,而不是對整個行集合執(zhí)行同一個操作。
2)提供對基于游標(biāo)位置的表中的行進行刪除和更新的能力。
3)游標(biāo)實際上作為面向集合的數(shù)據(jù)庫管理系統(tǒng)(rdbms)和面向行的程序設(shè)計之間的橋梁,使這兩種處理方式通過游標(biāo)溝通起來。
1.3 游標(biāo)的使用
講了這個多游標(biāo)的優(yōu)點,現(xiàn)在我們就親自來揭開游標(biāo)的神秘的面紗。
使用游標(biāo)的順序: 聲名游標(biāo)、打開游標(biāo)、讀取數(shù)據(jù)、關(guān)閉游標(biāo)、刪除游標(biāo)。
1.3.1聲明游標(biāo)
最簡單游標(biāo)聲明:declare <游標(biāo)名>cursor for<select語句>;
其中select語句可以是簡單查詢,也可以是復(fù)雜的接連查詢和嵌套查詢
例子:[已表2 addsalary為例子]
declare mycursor cursor for select * from addsalary
這樣我就對表addsalary申明了一個游標(biāo)mycursor
【高級備注】
declare <游標(biāo)名> [insensitive] [scroll] cursorfor<select語句>
這里我說一下游標(biāo)中級應(yīng)用中的[insensitive]和[scroll]
insensitive
表明ms sql server 會將游標(biāo)定義所選取出來的數(shù)據(jù)記錄存放在一臨時表內(nèi)(建立在tempdb 數(shù)據(jù)庫下)。對該游標(biāo)的讀取操作皆由臨時表來應(yīng)答。因此,對基本表的修改并不影響游標(biāo)提取的數(shù)據(jù),即游標(biāo)不會隨著基本表內(nèi)容的改變而改變,同時也無法通過游標(biāo)來更新基本表。如果不使用該保留字,那么對基本表的更新、刪除都會反映到游標(biāo)中。
另外應(yīng)該指出,當(dāng)遇到以下情況發(fā)生時,游標(biāo)將自動設(shè)定insensitive 選項。
a.在select 語句中使用distinct、 group by、 having union 語句;
b.使用outer join;
c.所選取的任意表沒有索引;
d.將實數(shù)值當(dāng)作選取的列。
scroll
表明所有的提取操作(如first、 last、 prior、 next、 relative、 absolute)都可用。如果不使用該保留字,那么只能進行next 提取操作。由此可見,scroll 極大地增加了提取數(shù)據(jù)的靈活性,可以隨意讀取結(jié)果集中的任一行數(shù)據(jù)記錄,而不必關(guān)閉再
重開游標(biāo)。
1.3.2 打開游標(biāo)
非常簡單,我們就打開剛才我們聲明的游標(biāo)mycursor
open mycursor
1.3.3讀取數(shù)據(jù)
fetch [ next | prior | first | last] from { 游標(biāo)名 | @游標(biāo)變量名 } [ into @變量名 [,…] ]
參數(shù)說明:
next 取下一行的數(shù)據(jù),并把下一行作為當(dāng)前行(遞增)。由于打開游標(biāo)后,行指針是指向該游標(biāo)第1行之前,所以第一次執(zhí)行fetch next操作將取得游標(biāo)集中的第1行數(shù)據(jù)。next為默認(rèn)的游標(biāo)提取選項。
into @變量名[,…] 把提取操作的列數(shù)據(jù)放到局部變量中。列表中的各個變量從左到右與游標(biāo)結(jié)果集中的相應(yīng)列相關(guān)聯(lián)。各變量的數(shù)據(jù)類型必須與相應(yīng)的結(jié)果列的數(shù)據(jù)類型匹配或是結(jié)果列數(shù)據(jù)類型所支持的隱性轉(zhuǎn)換。變量的數(shù)目必須與游標(biāo)選擇列表中的列的數(shù)目一致。
現(xiàn)在我們就取出mycursor游標(biāo)的數(shù)據(jù)吧!
當(dāng)游標(biāo)被打開時,行指針將指向該游標(biāo)集第1行之前,如果要讀取游標(biāo)集中的第1行數(shù)據(jù),必須移動行指針使其指向第1行。就本例而言,可以使用下列操作讀取第1行數(shù)據(jù):
eg: fetch next from mycursor 或則 fetch first from mycursor
這樣我就取出了游標(biāo)里的數(shù)據(jù),但是光光這樣可不夠,我們還需要將取出的數(shù)據(jù)賦給變量
//聲明2個變量
declare @o_id nvarchar(20)
declare @a_salary float
//將取出的值傳入剛才聲明的2個變量
fetch next from mycursor into @ o_id,@ a_salary
1.3.4關(guān)閉游標(biāo)
close mycursor
1.3.5刪除游標(biāo)
deallocate mycursor
1.3.6 實例訓(xùn)練
如上我介紹完了游標(biāo)使用的5個步驟,那現(xiàn)在我們就來上上手,練習(xí)用游標(biāo)取出表2 addsalary的數(shù)據(jù)。
為了運行我們自己創(chuàng)建的游標(biāo),我們將游標(biāo)寫在存儲過程里,方便我們看到游標(biāo)的整個使用過程。
在sqlserver2000中新建一個存儲過程:
create procedure pk_test
as
//聲明2個變量
declare @o_id nvarchar(20)
declare @a_salary float
//聲明一個游標(biāo)mycursor,select語句中參數(shù)的個數(shù)必須要和從游標(biāo)取出的變量名相同
declare mycursor cursor for select o_id,a_salary from addsalary
//打開游標(biāo)
open mycursor
//從游標(biāo)里取出數(shù)據(jù)賦值到我們剛才聲明的2個變量中
fetch next from mycursor into @o_id,@a_salary
//判斷游標(biāo)的狀態(tài)
//0 fetch語句成功
//-1 fetch語句失敗或此行不在結(jié)果集中
//-2被提取的行不存在
while (@@fetch_status=0)
begin
//顯示出我們每次用游標(biāo)取出的值
print \\\’游標(biāo)成功取出一條數(shù)據(jù)\\\’
print @o_id
print @a_salary
//用游標(biāo)去取下一條記錄
fetch next from mycursor into @o_id,@a_salary
end
//關(guān)閉游標(biāo)
close mycursor
//撤銷游標(biāo)
deallocate mycursor
go
通過上面的注釋,我想大家都明白了整個游標(biāo)的創(chuàng)建過程了吧。但是我們現(xiàn)在還是一個抽象的了解,我們學(xué)任何知識,都要用于實踐,這樣才能使抽象的東西變的具體。
那我們就運行這個存儲過程,看看游標(biāo)到底是怎么取值的:
我們打開sqlserver2000的查詢分析器,制定好數(shù)據(jù)庫后,我們執(zhí)行存儲過程
exec