游標(biāo)和游標(biāo)的優(yōu)點(diǎn) 在數(shù)據(jù)庫(kù)中,游標(biāo)是一個(gè)十分重要的概念。游標(biāo)提供了一種對(duì)從表中檢索出的數(shù)據(jù)進(jìn)行操作的靈活手段,就本質(zhì)而言,游標(biāo)實(shí)際上是一種能從包括多條數(shù)據(jù)記錄的結(jié)果集中每次提取一條記錄的機(jī)制。游標(biāo)總是與一條T_SQL 選擇語(yǔ)句相關(guān)聯(lián)因?yàn)橛螛?biāo)由結(jié)果集(可以是零條、一條或由相關(guān)的選擇語(yǔ)句檢索出的多條記錄)和結(jié)果集中指向特定記錄的游標(biāo)位置組成。當(dāng)決定對(duì)結(jié)果集進(jìn)行處理時(shí),必須聲明一個(gè)指向該結(jié)果集的游標(biāo)。如果曾經(jīng)用 C 語(yǔ)言寫(xiě)過(guò)對(duì)文件進(jìn)行處理的程序,那么游標(biāo)就像您打開(kāi)文件所得到的文件句柄一樣,只要文件打開(kāi)成功,該文件句柄就可代表該文件。對(duì)于游標(biāo)而言,其道理是相同的??梢?jiàn)游標(biāo)能夠?qū)崿F(xiàn)按與傳統(tǒng)程序讀取平面文件類似的方式處理來(lái)自基礎(chǔ)表的結(jié)果集,從而把表中數(shù)據(jù)以平面文件的形式呈現(xiàn)給程序。 我們知道關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)實(shí)質(zhì)是面向集合的,在MS SQL SERVER 中并沒(méi)有一種描述表中單一記錄的表達(dá)形式,除非使用where 子句來(lái)限制只有一條記錄被選中。因此我們必須借助于游標(biāo)來(lái)進(jìn)行面向單條記錄的數(shù)據(jù)處理。 由此可見(jiàn),游標(biāo)允許應(yīng)用程序?qū)Σ樵冋Z(yǔ)句select 返回的行結(jié)果集中每一行進(jìn)行相同或不同的操作,而不是一次對(duì)整個(gè)結(jié)果集進(jìn)行同一種操作;它還提供對(duì)基于游標(biāo)位置而對(duì)表中數(shù)據(jù)進(jìn)行刪除或更新的能力;而且,正是游標(biāo)把作為面向集合的數(shù)據(jù)庫(kù)管理系統(tǒng)和面向行的程序設(shè)計(jì)兩者聯(lián)系起來(lái),使兩個(gè)數(shù)據(jù)處理方式能夠進(jìn)行溝通。 游標(biāo)種類及用法 SQL SERVER 支持三種類型的游標(biāo):Transact_SQL 游標(biāo),API 服務(wù)器游標(biāo)和客戶游標(biāo)。 (1)Transact_SQL 游標(biāo) Transact_SQL 游標(biāo)是由DECLARE CURSOR 語(yǔ)法定義、主要用在Transact_SQL 腳本、存儲(chǔ)過(guò)程和觸發(fā)器中。Transact_SQL 游標(biāo)主要用在服務(wù)器上,由從客戶端發(fā)送給服務(wù)器的Transact_SQL 語(yǔ)句或是批處理、存儲(chǔ)過(guò)程、觸發(fā)器中的Transact_SQL 進(jìn)行管理。 Transact_SQL 游標(biāo)不支持提取數(shù)據(jù)塊或多行數(shù)據(jù)。 (2)API 游標(biāo) API 游標(biāo)支持在OLE DB, ODBC 以及DB_library 中使用游標(biāo)函數(shù),主要用在服務(wù)器上。每一次客戶端應(yīng)用程序調(diào)用API 游標(biāo)函數(shù),MS SQL SEVER 的OLE DB 提供者、ODBC驅(qū)動(dòng)器或DB_library 的動(dòng)態(tài)鏈接庫(kù)(DLL) 都會(huì)將這些客戶請(qǐng)求傳送給服務(wù)器以對(duì)API游標(biāo)進(jìn)行處理。 (3)客戶游標(biāo) 客戶游標(biāo)主要是當(dāng)在客戶機(jī)上緩存結(jié)果集時(shí)才使用。在客戶游標(biāo)中,有一個(gè)缺省的結(jié)果集被用來(lái)在客戶機(jī)上緩存整個(gè)結(jié)果集??蛻粲螛?biāo)僅支持靜態(tài)游標(biāo)而非動(dòng)態(tài)游標(biāo)。由于服務(wù)器游標(biāo)并不支持所有的Transact-SQL 語(yǔ)句或批處理,所以客戶游標(biāo)常常僅被用作服務(wù)器游標(biāo)的輔助。因?yàn)樵谝话闱闆r下,服務(wù)器游標(biāo)能支持絕大多數(shù)的游標(biāo)操作。 由于API 游標(biāo)和Transact-SQL 游標(biāo)使用在服務(wù)器端,所以被稱為服務(wù)器游標(biāo),也被稱為后臺(tái)游標(biāo),而客戶端游標(biāo)被稱為前臺(tái)游標(biāo)。在本章中我們主要講述服務(wù)器(后臺(tái))游標(biāo)。 每一個(gè)游標(biāo)必須有四個(gè)組成部分這四個(gè)關(guān)鍵部分必須符合下面的順序; 1.DECLARE 游標(biāo) 2.OPEN 游標(biāo) 3.從一個(gè)游標(biāo)中FETCH 信息 4.CLOSE 或DEALLOCATE 游標(biāo) 通常我們使用DECLARE 來(lái)聲明一個(gè)游標(biāo)聲明一個(gè)游標(biāo)主要包括以下主要內(nèi)容: 游標(biāo)名字 數(shù)據(jù)來(lái)源(表和列) 選取條件 屬性(僅讀或可修改) 其語(yǔ)法格式如下: DECLARE cursor_name [INSENSITIVE] [SCROLL] CURSOR FOR select_statement [FOR {READ ONLY | UPDATE [OF column_name [,...n]]}] 其中: cursor_name 指游標(biāo)的名字。 INSENSITIVE 表明MS SQL SERVER 會(huì)將游標(biāo)定義所選取出來(lái)的數(shù)據(jù)記錄存放在一臨時(shí)表內(nèi)(建立在tempdb 數(shù)據(jù)庫(kù)下)。對(duì)該游標(biāo)的讀取操作皆由臨時(shí)表來(lái)應(yīng)答。因此,對(duì)基本表的修改并不影響游標(biāo)提取的數(shù)據(jù),即游標(biāo)不會(huì)隨著基本表內(nèi)容的改變而改變,同時(shí)也無(wú)法通過(guò)游標(biāo)來(lái)更新基本表。如果不使用該保留字,那么對(duì)基本表的更新、刪除都會(huì)反映到游標(biāo)中。 另外應(yīng)該指出,當(dāng)遇到以下情況發(fā)生時(shí),游標(biāo)將自動(dòng)設(shè)定INSENSITIVE 選項(xiàng)。 在SELECT 語(yǔ)句中使用DISTINCT、 GROUP BY、 HAVING UNION 語(yǔ)句; 使用OUTER JOIN; 所選取的任意表沒(méi)有索引; 將實(shí)數(shù)值當(dāng)作選取的列。 SCROLL 表明所有的提取操作(如FIRST、 LAST、 PRIOR、 NEXT、 RELATIVE、 ABSOLUTE)都可用。如果不使用該保留字,那么只能進(jìn)行NEXT 提取操作。由此可見(jiàn),SCROLL 極大地增加了提取數(shù)據(jù)的靈活性,可以隨意讀取結(jié)果集中的任一行數(shù)據(jù)記錄,而不必關(guān)閉再重開(kāi)游標(biāo)。 select_statement是定義結(jié)果集的SELECT 語(yǔ)句。應(yīng)該注意的是,在游標(biāo)中不能使用COMPUTE、COMPU- TE BY、 FOR BROWSE、INTO 語(yǔ)句。 READ ONLY表明不允許游標(biāo)內(nèi)的數(shù)據(jù)被更新盡管在缺省狀態(tài)下游標(biāo)是允許更新的。而且在UPDATE或DELETE 語(yǔ)句的WHERE CURRENT OF 子句中,不允許對(duì)該游標(biāo)進(jìn)行引用。 UPDATE [OF column_name[,…n]] 定義在游標(biāo)中可被修改的列,如果不指出要更新的列,那么所有的列都將被更新。當(dāng)游標(biāo)被成功創(chuàng)建后,游標(biāo)名成為該游標(biāo)的惟一標(biāo)識(shí),如果在以后的存儲(chǔ)過(guò)程、觸發(fā)器或Transact_SQL 腳本中使用游標(biāo),必須指定該游標(biāo)的名字。 上面介紹的是SQL_92 的游標(biāo)語(yǔ)法規(guī)則。下面介紹MS SQL SERVER 提供的擴(kuò)展了的游標(biāo)聲明語(yǔ)法,通過(guò)增加另外的保留字,使游標(biāo)的功能進(jìn)一步得到了增強(qiáng)其語(yǔ)法規(guī)則為; LOCAL 定義游標(biāo)的作用域僅限在其所在的存儲(chǔ)過(guò)程、觸發(fā)器或批處理中。當(dāng)建立游標(biāo)的存儲(chǔ)過(guò)程執(zhí)行結(jié)束后,游標(biāo)會(huì)被自動(dòng)釋放。因此,我們常在存儲(chǔ)過(guò)程中使用OUTPUT 保留字,將游標(biāo)傳遞給該存儲(chǔ)過(guò)程的調(diào)用者,這樣在存儲(chǔ)過(guò)程執(zhí)行結(jié)束后,可以引用該游標(biāo)變量,在該種情況下,直到引用該游標(biāo)的最后一個(gè)就是被釋放時(shí),游標(biāo)才會(huì)自動(dòng)釋放。 GLOBAL 定義游標(biāo)的作用域是整個(gè)會(huì)話層會(huì)話層指用戶的連接時(shí)間它包括從用戶登錄到SQLSERVER 到脫離數(shù)據(jù)庫(kù)的整段時(shí)間。選擇GLOBAL 表明在整個(gè)會(huì)話層的任何存儲(chǔ)過(guò)程、觸發(fā)器或批處理中都可以使用該游標(biāo),只有當(dāng)用戶脫離數(shù)據(jù)庫(kù)、時(shí)該游標(biāo)才會(huì)被自動(dòng)釋放。 注意:如果既未使用GLOBAL也未使用LOCAL,那么SQL SERVER將使用default local cursor數(shù)據(jù)庫(kù)選項(xiàng),為了與以彰的版本歉容,該選項(xiàng)常設(shè)置為FALSE。 FORWARD_ONLY 選項(xiàng)指明在從游標(biāo)中提取數(shù)據(jù)記錄時(shí),只能按照從第一行到最后一行的順序,此時(shí)只能選用FETCH NEXT 操作。除非使用STATIC, KEYSET 和DYNAMIC 關(guān)鍵字,否則如果未指明是使用FORWARD_ONLY 還是使用SCROLL, 那么FORWARD_ONLY 將成為缺省選項(xiàng),因?yàn)槿羰褂肧TATIC KEYSET 和DYNAMIC 關(guān)鍵字,則變成了SCROLL 游標(biāo)。另外如果使用了FORWARD_ONLY, 便不能使用FAST_FORWARD。 STATIC 選項(xiàng)的含義與INSENSITIVE 選項(xiàng)一樣,MS SQL SERVER 會(huì)將游標(biāo)定義所選取出來(lái)的數(shù)據(jù)記錄存放在一臨時(shí)表內(nèi)(建立在tempdb 數(shù)據(jù)庫(kù)下)。對(duì)該游標(biāo)的讀取操作皆由臨時(shí)表來(lái)應(yīng)答。因此對(duì)基本表的修改并不影響游標(biāo)中的數(shù)據(jù),即游標(biāo)不會(huì)隨著基本表內(nèi)容的改變而改變,同時(shí)也無(wú)法通過(guò)游標(biāo)來(lái)更新基本表。 KEYSET 指出當(dāng)游標(biāo)被打開(kāi)時(shí),游標(biāo)中列的順序是固定的,并且MS SQL SERVER 會(huì)在tempdb內(nèi)建立一個(gè)表,該表即為KEYSET KEYSET 的鍵值可惟一識(shí)別游標(biāo)中的某行數(shù)據(jù)。當(dāng)游標(biāo)擁有者或其它用戶對(duì)基本表中的非鍵值數(shù)據(jù)進(jìn)行修改時(shí),這種變化能夠反映到游標(biāo)中,所以游標(biāo)用戶或所有者可以通過(guò)滾動(dòng)游標(biāo)提限這些數(shù)據(jù)。 當(dāng)其它用戶增加一條新的符合所定義的游標(biāo)范圍的數(shù)據(jù)時(shí),無(wú)法由此游標(biāo)讀到該數(shù)據(jù)。因?yàn)門ransact-SQL 服務(wù)器游標(biāo)不支持INSERT 語(yǔ)句。 如果在游標(biāo)中的某一行被刪除掉,那么當(dāng)通過(guò)游標(biāo)來(lái)提取該刪除行時(shí),@@FETCH_STATUS 的返回值為-2。 @@FETCH_STATUS 是用來(lái)判斷讀取游標(biāo)是否成功的系統(tǒng)全局變量。 由于更新操作包括兩部分:刪除原數(shù)據(jù)插入新數(shù)據(jù),所以如果讀取原數(shù)據(jù),@@FETCH_STATUS 的返回值為-2; 而且無(wú)法通過(guò)游標(biāo)來(lái)讀取新插入的數(shù)據(jù)。但是如果使用了WHERE CURRENT OF 子句時(shí),該新插入行數(shù)據(jù)便是可見(jiàn)的。 注意:如果基礎(chǔ)表未包含惟一的索引或主鍵,則一個(gè)KEYSET游標(biāo)將回復(fù)成STATIC游標(biāo)。 DYNAMIC 指明基礎(chǔ)表的變化將反映到游標(biāo)中,使用這個(gè)選項(xiàng)會(huì)最大程度上保證數(shù)據(jù)的一致性。然而,與KEYSET 和STATIC 類型游標(biāo)相比較,此類型游標(biāo)需要大量的游標(biāo)資源。 FAST_FORWARD 指明一個(gè)FORWARD_ONLY, READ_ONLY 型游標(biāo)。此選項(xiàng)已為執(zhí)行進(jìn)行了優(yōu)化。如果SCROLL 或FOR_UPDATE 選項(xiàng)被定義,則FAST_FORWARD 選項(xiàng)不能被定義。 SCROLL_LOCKS 指明鎖被放置在游標(biāo)結(jié)果集所使用的數(shù)據(jù)上當(dāng)。數(shù)據(jù)被讀入游標(biāo)中時(shí),就會(huì)出現(xiàn)鎖。這個(gè)選項(xiàng)確保對(duì)一個(gè)游標(biāo)進(jìn)行的更新和刪除操作總能被成功執(zhí)行。如果FAST_FORWARD選項(xiàng)被定義,則不能選擇該選項(xiàng)。另外,由于數(shù)據(jù)被游標(biāo)鎖定,所以當(dāng)考慮到數(shù)據(jù)并發(fā)處理時(shí),應(yīng)避免使用該選項(xiàng)。 OPTIMISTIC 指明在數(shù)據(jù)被讀入游標(biāo)后,如果游標(biāo)中某行數(shù)據(jù)已發(fā)生變化,那么對(duì)游標(biāo)數(shù)據(jù)進(jìn)行更新或刪除可能會(huì)導(dǎo)致失敗。如果使用了FAST_FORWARD 選項(xiàng),則不能使用該選項(xiàng)。 TYPE_WARNING 指明若游標(biāo)類型被修改成與用戶定義的類型不同時(shí),將發(fā)送一個(gè)警告信息給客戶端。 注意:不可以將SQL_92的游標(biāo)語(yǔ)法規(guī)則與MS SQL SERVER的游標(biāo)擴(kuò)展用法混合在一起使用。 下面我們將總結(jié)一下聲明游標(biāo)時(shí)應(yīng)注意的一些問(wèn)題。 如果在CURSOR 前使用了SCROLL 或INSENSITIVE 保留字,則不能在CURSOR 和FOR select_statement 之間使用任何的保留字。反之同理。 如果用DECLARE CURSOR 聲明游標(biāo)時(shí),沒(méi)有選擇READ_ONLY、 OPTIMISTIC 或SCROLL_LOCKS 選項(xiàng)時(shí),游標(biāo)的缺省情況為: 如果SELECT 語(yǔ)句不支持更新,則游標(biāo)為READ_ONLY; STATIC 和FAST_FORWARD 類型的游標(biāo)缺省為READ_ONLY; DYNAMIC 和KEYSET 游標(biāo)缺省為OPTIMISTIC。 我們僅能在Transact-SQL 語(yǔ)句中引用游標(biāo),而不能在數(shù)據(jù)庫(kù)API 函數(shù)中引用。 游標(biāo)被聲明以后,可以通過(guò)系統(tǒng)過(guò)程對(duì)其特性進(jìn)行設(shè)置。 對(duì)那些有權(quán)限對(duì)視圖、表或某些列執(zhí)行SELECT 語(yǔ)句的用戶而言,它也具有使用游標(biāo)的缺省權(quán)限。 打開(kāi)游標(biāo)游標(biāo)在聲明以后,如果要從游標(biāo)中讀取數(shù)據(jù)必須打開(kāi)游標(biāo)。打開(kāi)一個(gè)Transact-SQL服務(wù)器游標(biāo)使用OPEN 命令,其語(yǔ)法規(guī)則為: OPEN { { [GLOBAL] cursor_name } | cursor_variable_name} 各參數(shù)說(shuō)明如下: GLOBAL 定義游標(biāo)為一全局游標(biāo)。 cursor_name 為聲明的游標(biāo)名字。如果一個(gè)全局游標(biāo)和一個(gè)局部游標(biāo)都使用同一個(gè)游標(biāo)名,則如果使用GLOBAL 便表明其為全局游標(biāo),否則表明其為局部游標(biāo)。 cursor_variable_name 為游標(biāo)變量。當(dāng)打開(kāi)一個(gè)游標(biāo)后時(shí),MS SQL SERVER 首先檢查聲明游標(biāo)的語(yǔ)法是否正確,如果游標(biāo)聲明中有變量,則將變量值帶入。 在打開(kāi)游標(biāo)時(shí),如果游標(biāo)聲明語(yǔ)句中使用了INSENSITIVE 或STATIC 保留字,則OPEN產(chǎn)生一個(gè)臨時(shí)表來(lái)存放結(jié)果集;如果在結(jié)果集中任何一行數(shù)據(jù)的大小超過(guò)MS SQL SERVER定義的最大行尺寸時(shí),OPEN 命令將失??;如果聲明游標(biāo)時(shí)作用了KEYSET 選項(xiàng),則OPEN 產(chǎn)生一個(gè)臨時(shí)表來(lái)存放鍵值。所有的臨時(shí)表都存在tempdb 數(shù)據(jù)庫(kù)中。 在游標(biāo)被成功打開(kāi)之后,@@CURSOR_ROWS 全局變量將用來(lái)記錄游標(biāo)內(nèi)數(shù)據(jù)行數(shù)。為了提高性能,MS SQL SERVER 允許以異步方式從基礎(chǔ)表向KEYSET 或靜態(tài)游標(biāo)讀入數(shù)據(jù),即如果MS SQL SERVER 的查詢優(yōu)化器估計(jì)從基礎(chǔ)表中返回給游標(biāo)的數(shù)據(jù)行已經(jīng)超過(guò)sp_configure cursor threshold 參數(shù)值,則MS SQL SERVER 將啟動(dòng)另外一個(gè)獨(dú)立的線程來(lái)繼續(xù)從基礎(chǔ)表中讀入符合游標(biāo)定義的數(shù)據(jù)行,此時(shí)可以從游標(biāo)。中讀取數(shù)據(jù)進(jìn)行處理而不必等到所有的符合游標(biāo)定義的數(shù)據(jù)行都從基礎(chǔ)表中讀入游標(biāo) @@CURSOR_ROWS 變量存儲(chǔ)的正是在調(diào)用@@CURSOR_ROWS 時(shí),游標(biāo)已從基礎(chǔ)表讀入的數(shù)據(jù)行。@@CURSOR_ROWS 的返回值有以下四個(gè),如表13-1 所示。 如果所打開(kāi)的游標(biāo)在聲明時(shí)帶有SCROLL 或INSENSITIVE 保留字,那么@@CURSOR_ROWS 的值為正數(shù)且為該游標(biāo)的所有數(shù)據(jù)行。如果未加上這兩個(gè)保留字中的一個(gè),則@@CURSOR_ROWS 的值為-1, 說(shuō)明該游標(biāo)內(nèi)只有一條數(shù)據(jù)記錄。 當(dāng)游標(biāo)被成功打開(kāi)以后,就可以從游標(biāo)中逐行地讀取數(shù)據(jù),以進(jìn)行相關(guān)處理。從游標(biāo)中讀取數(shù)據(jù)主要使用FETCH 命令。其語(yǔ)法規(guī)則為: 各參數(shù)含義說(shuō)明如下: NEXT 返回結(jié)果集中當(dāng)前行的下一行,并增加當(dāng)前行數(shù)為返回行行數(shù)。如果FETCH NEXT是第一次讀取游標(biāo)中數(shù)據(jù),則返回結(jié)果集中的是第一行而不是第二行。 PRIOR 返回結(jié)果集中當(dāng)前行的前一行,并減少當(dāng)前行數(shù)為返回行行數(shù)。如果FETCH PRIOR是第一次讀取游標(biāo)中數(shù)據(jù),則無(wú)數(shù)據(jù)記錄返回,并把游標(biāo)位置設(shè)為第一行。 FIRST 返回游標(biāo)中第一行。 LAST 返回游標(biāo)中的最后一行。 ABSOLUTE {n | @nvar} 如果n 或@nvar 為正數(shù),則表示從游標(biāo)中返回的數(shù)據(jù)行數(shù)。如果n 或@nvar 為負(fù)數(shù),則返回游標(biāo)內(nèi)從最后一行數(shù)據(jù)算起的第n 或@nvar 行數(shù)據(jù)。若n 或@nvar 超過(guò)游標(biāo)的數(shù)據(jù)子集范疇,則@@FETCH_STARS 返回-1, 在該情況下,如果n 或@nvar 為負(fù)數(shù),則執(zhí)行FETCH NEXT 命令會(huì)得到第一行數(shù)據(jù),如果n 或@nvar為正值,執(zhí)行FETCH PRIOR 命令則會(huì)得到最后一行數(shù)據(jù)。n 或@nvar 可以是一固定值也可以是一smallint, tinyint 或int 類型的變量。 RELATIVE {n | @nvar} 若n 或@nvar 為正數(shù),則讀取游標(biāo)當(dāng)前位置起向后的第n 或@nvar 行數(shù)據(jù);如果n 或@nvar 為負(fù)數(shù),則讀取游標(biāo)當(dāng)前位置起向前的第n 或@nvar 行數(shù)據(jù)。若n 或@nvar 超過(guò)游標(biāo)的數(shù)據(jù)子集范疇,則@@FETCH_STARS 返回-1, 在該情況下,如果n 或@nvar 為負(fù)數(shù),則執(zhí)行FETCH NEXT 命令則會(huì)得到第一行數(shù)據(jù);如果n 或@nvar 為正值,執(zhí)行FETCH PRIOR 命令則會(huì)得到最后一行數(shù)據(jù)。n 或@nvar 可以是一固定值也可以是一smallint, tinyint或int 類型的變量。 INTO @variable_name[,...n] 允許將使用FETCH 命令讀取的數(shù)據(jù)存放在多個(gè)變量中。在變量行中的每個(gè)變量必須與游標(biāo)結(jié)果集中相應(yīng)的列相對(duì)應(yīng),每一變量的數(shù)據(jù)類型也要與游標(biāo)中數(shù)據(jù)列的數(shù)據(jù)類型相匹配。 @@FETCH_STATUS 全局變量返回上次執(zhí)行FETCH 命令的狀態(tài)。在每次用FETCH從游標(biāo)中讀取數(shù)據(jù)時(shí),都應(yīng)檢查該變量,以確定上次FETCH 操作是否成功,來(lái)決定如何進(jìn)行下一步處理。@@FETCH_STATUS 變量有三個(gè)不同的返回值,如表13-2。 在使用FETCH 命令從游標(biāo)中讀取數(shù)據(jù)時(shí),應(yīng)該注意以下的情況: 當(dāng)使用SQL-92 語(yǔ)法來(lái)聲明一個(gè)游標(biāo)時(shí),沒(méi)有選擇SCROLL 選項(xiàng)時(shí),只能使用FETCH NEXT 命令來(lái)從游標(biāo)中讀取數(shù)據(jù),即只能從結(jié)果集第一行按順序地每次讀取一行,由于不能使用FIRST、 LAST、 PRIOR, 所以無(wú)法回滾讀取以前的數(shù)據(jù)。如果選擇了SCROLL 選項(xiàng),則可能使用所有的FETCH 操作。 當(dāng)使用MS SQL SERVER 的擴(kuò)展語(yǔ)法時(shí),必須注意以下約定: 如果定義了FORWARD-ONLY 或FAST_FORWARD 選項(xiàng),則只能使用FETCH NEXT命令; 如果沒(méi)有定義DYNAMIC, FORWARD_ONLY 或FAST_FORWARD 選項(xiàng),而定義了KEYSET, STATIC 或SCROLL 中的任何一個(gè),則可使用所有的FETCH 操作;DYNAMIC SCROLL 游標(biāo)支持所有的FETCH, 選項(xiàng)但禁用ABSOLUTE 選項(xiàng)。 關(guān)閉游標(biāo) 1、使用CLOSE 命令關(guān)閉游標(biāo) 在處理完游標(biāo)中數(shù)據(jù)之后必須關(guān)閉游標(biāo)來(lái)釋放數(shù)據(jù)結(jié)果集和定位于數(shù)據(jù)記錄上的鎖。CLOSE 語(yǔ)句關(guān)閉游標(biāo),但不釋放游標(biāo)占用的數(shù)據(jù)結(jié)構(gòu)。如果準(zhǔn)備在隨后的使用中再次打開(kāi)游標(biāo),則應(yīng)使用CLOSE 命令。其關(guān)閉游標(biāo)的語(yǔ)法規(guī)則為: CLOSE { { [GLOBAL] cursor_name } | cursor_variable_name } 2、自動(dòng)關(guān)閉游標(biāo) 我們已經(jīng)了解到游標(biāo)可應(yīng)用在存儲(chǔ)過(guò)程、觸發(fā)器和Transact_SQL腳本中。如果在聲明游標(biāo)與釋放游標(biāo)之間使用了事務(wù)結(jié)構(gòu),則在結(jié)束事務(wù)時(shí)游標(biāo)會(huì)自動(dòng)關(guān)閉。其具體的情況如下所示: (1)、聲明一個(gè)游標(biāo) (2)、打開(kāi)游標(biāo) (3)、讀取游標(biāo) (4)、BEGIN TRANSATION (5)、數(shù)據(jù)處理 (6)、COMMIT TRANSATION (7)、回到步驟3 在這樣的應(yīng)用環(huán)境中。當(dāng)從游標(biāo)中讀取一條數(shù)據(jù)記錄進(jìn)行以BEGIN TRANSATION為開(kāi)頭,COMMIT TRANSATION 或ROLLBACK 為結(jié)束的事務(wù)處理時(shí),在程序開(kāi)始運(yùn)行后,第一行數(shù)據(jù)能夠被正確返回,經(jīng)由步驟7, 程序回到步驟3, 讀取游標(biāo)的下一行,此時(shí)常會(huì)發(fā)現(xiàn)游標(biāo)未打開(kāi)的錯(cuò)誤信息。其原因就在于當(dāng)一個(gè)事務(wù)結(jié)束時(shí),不管其是以COMMIT TRANSATION 還是以ROLLBACK TRANSATION 結(jié)束,MS SQL SERVER 都會(huì)自動(dòng)關(guān)閉游標(biāo),所以當(dāng)繼續(xù)從游標(biāo)中讀取數(shù)據(jù)時(shí)就會(huì)造成錯(cuò)誤。 解決這種錯(cuò)誤的方法就是使用SET 命令將CURSOR_CLOSE_ON_COMMIT 這一參數(shù)設(shè)置為OFF 狀態(tài)。其目的就是讓游標(biāo)在事務(wù)結(jié)束時(shí)仍繼續(xù)保持打開(kāi)狀態(tài),而不會(huì)被關(guān)閉。使用SET 命令的格式為: SET CURSOR_CLOSE_ON_COMMIT OFF 釋放游標(biāo) 在使用游標(biāo)時(shí),各種針對(duì)游標(biāo)的操作或者引用游標(biāo)名,或者引用指向游標(biāo)的游標(biāo)變量。當(dāng)CLOSE 命令關(guān)閉游標(biāo)時(shí),并沒(méi)有釋放游標(biāo)占用的數(shù)據(jù)結(jié)構(gòu)。因此常使用DEALLOCATE 命令。通過(guò)該命令可以刪除掉游標(biāo)與游標(biāo)名或游標(biāo)變量之間的聯(lián)系,并且釋放游標(biāo)占用的所有系統(tǒng)資源。其語(yǔ)法規(guī)則為: DEALLOCATE { { [GLOBAL] cursor_name } | @cursor_variable_name} 當(dāng)使用DEALLOCATE @cursor_variable_name 來(lái)刪除游標(biāo)時(shí),游標(biāo)變量并不會(huì)被釋放,除非超過(guò)使用該游標(biāo)的存儲(chǔ)過(guò)程、觸發(fā)器的范圍(即游標(biāo)的作用域)。 |
|
來(lái)自: lvyafei > 《.NET技術(shù)》