SqlServer遊標的建立與使用

學習中的苦與樂發表於2021-04-08

前言

大家都對SqlServer檢視、儲存過程、觸發器的建立與使用有一定的瞭解了,我們來看下什麼是遊標,怎麼使用,什麼時候用。

SqlServer檢視的建立與使用

SqlServer儲存過程的建立與使用

SqlServer觸發器的建立與使用


 

什麼是遊標

1、遊標的概念

 

遊標(Cursor)是處理資料的一種方法,為了檢視或者處理結果集中的資料,遊標提供了在結果集中一次一行或者多行前進或向後瀏覽資料的能力

它使使用者可逐行訪問由SQL Server返回的結果集。使用遊標(cursor)的一個主要的原因就是把集合操作轉換成單個記錄處理方式。

用SQL語言從資料庫中檢索資料後,結果放在記憶體的一塊區域中,且結果往往是一個含有多個記錄的集合。

遊標機制允許使用者在SQL server內逐行地訪問這些記錄,按照使用者自己的意願來顯示和處理這些記錄。

我們可以把遊標當作一個指標,它可以指定結果中的任何位置,然後允許使用者對指定位置的資料進行處理。

2、遊標的組成

遊標包含兩個部分:一個是遊標結果集、一個是遊標位置。

遊標結果集:定義該遊標得SELECT語句返回的行的集合。遊標位置:指向這個結果集某一行的當前指標。

3、遊標的分類

遊標共有3類:API伺服器遊標、Transaction-SQL遊標和API客戶端遊標。

其中前兩種遊標都是執行在伺服器上的,所以又叫做伺服器遊標。

API伺服器遊標

API伺服器遊標主要應用在服務上,當客戶端的應用程式呼叫API遊標函式時,伺服器會對API函式進行處理。使用API函式和方法可以實現如下功能:

(1)開啟一個連線。

(2)設定定義遊標特徵的特性或屬性,API自動將遊標對映到每個結果集。

(3)執行一個或多個Transaction-SQL語句。

(4)使用API函式或方法提取結果集中的行。

API伺服器遊標包含以下四種:靜態遊標、動態遊標、只進遊標、鍵集驅動遊標(Primary key)

靜態遊標的完整結果集將開啟遊標時建立的結果集儲存在臨時表中,(靜態遊標始終是隻讀的)。靜態遊標具有以下特點:總是按照開啟遊標時的原樣顯示結果集;不反映資料庫中作的任何修改,也不反映對結果集行的列值所作的更改;不顯示開啟遊標後在資料庫中新插入的行;組成結果集的行被其他使用者更新,新的資料值不會顯示在靜態遊標中;但是靜態遊標會顯示開啟遊標以後從資料庫中刪除的行。

動態遊標與靜態遊標相反,當滾動遊標時動態遊標反映結果集中的所有更改。結果集中的行資料值、順序和成員每次提取時都會改變。

只進遊標不支援滾動,它只支援遊標從頭到尾順序提取資料行。注意:只進遊標也反映對結果集所做的所有更改。

鍵集驅動遊標同時具有靜態遊標和動態遊標的特點。當開啟遊標時,該遊標中的成員以及行的順序是固定的,鍵集在遊標開啟時也會儲存到臨時工作表中,對非鍵集列的資料值的更改在使用者遊標滾動的時候可以看見,在遊標開啟以後對資料庫中插入的行是不可見的,除非關閉重新開啟遊標。

 

Transaction-SQL遊標

該遊標是基於Declare Cursor 語法,主要用於Transaction-SQL指令碼、儲存過程以及觸發器中。Transaction-SQL遊標在伺服器處理由客戶端傳送到伺服器的Transaction-SQL語句。

在儲存過程或觸發器中使用Transaction-SQL遊標的過程為:

(1)宣告Transaction-SQL變數包含遊標返回的資料。為每個結果集列宣告一個變數。宣告足夠大的變數來儲存列返回的值,並宣告變數的型別為可從資料型別隱式轉換得到的資料型別。

(2)使用Declare Cursor語句將Transaction-SQL遊標與Select語句相關聯。還可以利用Declare Cursor定義遊標的只讀、只進等特性。 

(3)使用Open語句執行Select語句填充遊標。

(4)使用Fetch Into語句提取單個行,並將每列中得資料移至指定的變數中。注意:其他Transaction-SQL語句可以引用那些變數來訪問提取的資料值。Transaction-SQL遊標不支援提取行塊。

(5)使用Close語句結束遊標的使用。注意:關閉遊標以後,該遊標還是存在,可以使用Open命令開啟繼續使用,只有呼叫Deallocate語句才會完全釋放。

 

客戶端遊標

該遊標將使用預設結果集把整個結果集快取記憶體在客戶端上,所有的遊標操作都在客戶端的快取記憶體中進行。

注意:客戶端遊標只支援只進和靜態遊標。不支援其他遊標。


 

怎麼使用遊標

遊標的生命週期包含有五個階段,也是它使用的順序:

  1. 宣告遊標(建立);
  2. 開啟遊標;
  3. 讀取遊標資料;
  4. 關閉遊標;
  5. 釋放遊標。

 

1、宣告遊標

宣告遊標是為遊標指定獲取資料時所使用的Select語句,宣告遊標並不會檢索任何資料,它只是為遊標指明瞭相應的Select 語句。

在SQL Server中建立遊標物件使用關鍵之declare(變數宣告)以及curosr(遊標)。

宣告遊標的引數

(1)Local與Global:Local表示遊標的作用於僅僅限於其所在的儲存過程、觸發器以及批處理中、執行完畢以後遊標自動釋放。Global表示的是該遊標作用域是整個會話層。由連線執行的任何儲存過程、批處理等都可以引用該遊標名稱,僅在斷開連線時隱性釋放。

(2)Forward_only與Scroll:前者表示為只進遊標,後者表示為可以隨意定位。預設為前者。

(3)Static、Keyset與Dynamic: 第一個表示定義一個遊標,其資料存放到一個臨時表內,對遊標的所有請求都從臨時表中應答,因此,對該遊標進行提取操作時返回的資料不反映對基表所作的修改,並且該遊標不允許修改。Keyset表示的是,當遊標開啟時,鍵集驅動遊標中行的身份與順序是固定的,並把其放到臨時表中。Dynamic表示的是滾動遊標時,動態遊標反映對結果集內所有資料的更改。

(4)Read_only 、Scroll_Locks與Optimistic:第一個表示的是隻讀遊標,第二個表示的是在使用的遊標結果集資料上放置鎖,當行讀取到遊標中然後對它們進行修改時,資料庫將鎖定這些行,以保證資料的一致性。Optimistic的含義是遊標將資料讀取以後,如果這些資料被更新了,則通過遊標定位進行的更新與刪除操作將不會成功。

標準遊標:

declare
MyCursor cursor
for select Name,ClassId from a_Students

只讀遊標

declare
MyCursor cursor
for SELECT s.Name,sc.ClassName FROM a_Students s
INNER JOIN a_StudentClass sc ON s.ClassId=sc.ClassId
For Read Only

可更新遊標

declare
MyCursor cursor
for SELECT s.Name,sc.ClassName FROM a_Students s
INNER JOIN a_StudentClass sc ON s.ClassId=sc.ClassId
For UpDate

--宣告(建立)遊標物件(標準遊標)
declare 
MyCursor cursor 
for SELECT s.Name,sc.ClassName FROM a_Students s
INNER JOIN a_StudentClass sc ON s.ClassId=sc.ClassId;

 

2、開啟遊標物件

開啟遊標使用Open語句用於開啟Transaction-SQL伺服器遊標,執行Open語句的過程中就是按照Select語句進行填充資料,開啟遊標以後遊標位置在第一行。

開啟遊標

全域性遊標:Open Global MyCursor 區域性遊標: Open MyCursor

遊標物件建立之後,必須開啟之後才能進行使用,使用關鍵字open。

--開啟遊標
open MyCursor;

3、讀取遊標資料

在開啟遊標以後,使用Fetch語句從Transaction-SQL伺服器遊標中檢索特定的一行。使用Fetch操作,可以使遊標移動到下一個記錄,並將遊標返回的每個列得資料分別賦值給宣告的本地變數。

Fetch [Next | Prior | First | Last | Absolute n | Relative n ] From MyCursor

Into @GoodsID,@GoodsName

其中:Next表示返回結果集中當前行的下一行記錄,如果第一次讀取則返回第一行。預設的讀取選項為Next

Prior表示返回結果集中當前行的前一行記錄,如果第一次讀取則沒有行返回,並且把遊標置於第一行之前。

First表示返回結果集中的第一行,並且將其作為當前行。

Last表示返回結果集中的最後一行,並且將其作為當前行。

Absolute n 如果n為正數,則返回從遊標頭開始的第n行,並且返回行變成新的當前行。如果n為負,則返回從遊標末尾開始的第n行,並且返回行為新的當前行,如果n為0,則返回當前行。

Relative n 如果n為正數,則返回從當前行開始的第n行,如果n為負,則返回從當前行之前的第n行,如果為0,則返回當前行。

 

--讀取遊標資料
--宣告兩個變數接收從遊標中取出的值
declare @Name varchar(50),@ClassName varchar(50);    
    --移動遊標取值
    fetch next from MyCursor into @Name,@ClassName;
    print(@Name);
    print(@ClassName);

4、關閉遊標

遊標使用完畢之後需要關閉,以及資源的釋放,關鍵字close,deallocate。

--關閉遊標
CLOSE MyCursor

 

5、釋放遊標

遊標使用完畢之後需要關閉,以及資源的釋放,關鍵字close,deallocate。

--釋放遊標
DEALLOCATE MyCursor

 

6、修改遊標資料

--修改當前遊標資料
--a_Students表名,Name欄位名,MyCursor遊標名
UpDate a_Students Set Name = '孫悟空111' Where CURRENT Of MyCursor;

7、刪除遊標資料

--刪除當前遊標資料
--a_Students表名
Delete From a_Students Where Current Of MyCursor

 

完整例項

使用遊標查詢資料,只獲取取欄位姓名(Name),和欄位班級(ClassName)

--宣告(建立)遊標物件(標準遊標)
declare 
MyCursor cursor 
for SELECT  s.Name,sc.ClassName FROM a_Students s
INNER JOIN a_StudentClass sc ON s.ClassId=sc.ClassId;

--宣告兩個變數接收從遊標中取出的值
declare @Name varchar(50),@ClassName varchar(50);    
begin
    --開啟遊標
    open MyCursor;

    --移動遊標取值
    fetch next from MyCursor into @Name,@ClassName;
    --這裡對遊標的狀態進行判斷,如果為0,證明遊標中有值
    while @@FETCH_STATUS = 0
        BEGIN
            print(@Name);
            print(@ClassName);
            --讓遊標繼續往後移動
            fetch next from MyCursor into @Name,@ClassName
        end

--關閉遊標
CLOSE MyCursor

--釋放遊標
DEALLOCATE MyCursor

end

 


 

什麼時候使用遊標

當你要處理的結果集比較龐大,而你要對某一行或幾行進行操作的時候,要考慮使用遊標。

特別是對結果集中第幾行進行行操作的時候,一般可以考慮使用遊標。

但也不是唯一的方法,可以利用別的方法來替代,一般比較複雜的儲存過程裡面會出現遊標的影子。

  1. 現存系統有一些遊標,我們查詢必須通過遊標來實現
  2. 作為一個備用方式,當我們窮盡了while迴圈,子查詢,臨時表,表變數,自建函式或其他方式扔來無法實現某些查詢的時候,使用遊標實現.

 

遊標使用的建議

遊標用於按順序遍歷結果集。

但一般情況下,應儘量避免使用遊標。

原因:

  1.  遊標違背了關係模型,即按集合來考慮問題的思想;
  2. 遊標逐行對紀錄進行操作,會帶來額外的開銷,使用遊標的解決方案通常比使用集合的解決方案要慢得多;
  3. 使用遊標的解決方案,需要用很多程式碼來描述對遊標的操作,因此程式碼更長,可讀性更差,也更難以維護。

如果要使用,一定記住要記住:

  1. 用完之後一定要關閉和釋放,儘量不要在大量資料上定義遊標;
  2. 儘量不要使用遊標上更新資料;
  3. 儘量不要使用insensitive, static和keyset這些引數定義遊標;
  4. 如果可以,儘量使用FAST_FORWARD關鍵字定義遊標;
  5. 如果只對資料進行讀取,當讀取時只用到FETCH NEXT選項,則最好使用FORWARD_ONLY引數。

 


我們就介紹到這裡吧,各位拜了個拜。

 

歡迎關注訂閱微信公眾號【熊澤有話說】,更多好玩易學知識等你來取
作者:熊澤-學習中的苦與樂
公眾號:熊澤有話說
出處: https://www.cnblogs.com/xiongze520/p/14633171.html
創作不易,任何人或團體、機構全部轉載或者部分轉載、摘錄,請在文章明顯位置註明作者和原文連結。  

 

相關文章