SQLServer游標詳解


一、游標概念

      我們知道,關系數據庫所有的關系運算其實是集合與集合的運算,它的輸入是集合輸出同樣是集合,有時需要對結果集逐行進行處理,這時就需要用到游標。我們對游標的使用一本遵循“五步法”:聲明游標—>打開游標—>讀取數據—>關閉游標—>刪除游標。以下就從這五步對游標的使用進行說明,並給出具體實例。

二、“五步法”講解

1、聲明游標(DECLARE CURSOR)

(1) DECLARE CURSOR 既接受基於 ISO 標准的語法,也接受使用一組 Transact-SQL 擴展的語法。

ISO 語法
DECLARE cursor_name [ INSENSITIVE ] [ SCROLL ] CURSOR 
     FOR select_statement 
     [ FOR { READ ONLY | UPDATE [ OF column_name [ ,...n ] ] } ]
[;]


Transact-SQL 擴展語法
DECLARE cursor_name CURSOR [ LOCAL | GLOBAL ] (說明游標的“作用域”)
     [ FORWARD_ONLY | SCROLL ] (說明游標的“方向”)
     [ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ] (“說明游標的“類型”)
     [ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ] 
     [ TYPE_WARNING ] 
     FOR select_statement 
     [ FOR UPDATE [ OF column_name [ ,...n ] ] ]
[;] 

下面只對“T-SQL擴展語法”進行介紹,主要游標介紹作用域、方向及類型

(2)游標的作用域 

LOCAL

      說明所聲明的游標為局部的,其作用域為創建它的批處理、存儲過程或觸發器,即在批處理、調用它的存儲過程或觸發器執行完成后,該游標被系統隱式釋放。但,若游標作為存儲過程OUTPUT 的輸出參數,在存儲過程終止后給游標變量分配參數可以繼續引用游標,如果 OUTPUT 參數將游標傳遞回來,則游標在最后引用它的變量釋放或離開作用域時釋放。

GLOBAL

      指定該游標的作用域對來說連接是全局的。在由連接執行的任何存儲過程或批處理中,都可以引用該游標名稱。該游標僅在斷開連接時隱式釋放。

      注意:如果 GLOBAL 和 LOCAL 參數都未指定,則默認值由 default to local cursor 數據庫選項的設置控制。在 SQL Server 7.0 版中,該選項默認為 FALSE,以便與 SQL Server 的早期版本匹配,在早期版本中,所有游標都是全局的。

 

declare testcur cursor --聲明時未指定"local"或"global"關鍵字,系統默認游標是"global(全局)"的.
for 
select 學號,姓名 from XSB
GO
open testcur   
fetch next from testcur
GO
--------------------------------------------
declare testcur cursor local   --聲明時指定"local"關鍵字
for 
select 學號,姓名 from XSB
open testcur   
fetch next from testcur
GO    --在這個批處理結束后,游標自動釋放,即失效
-----------------------------------------------
declare testcur1 cursor local  --聲明時指定"local"關鍵字
for 
select 學號,姓名 from XSB
GO  --在這個批處理后,游標就失效了,后面對游標操作時,提示"名為 'testcur1' 的游標不存在"錯誤.
open testcur1   
fetch next from testcur1
GO

(3)游標方向

FORWARD_ONLY

      指定游標只能從第一行滾動到最后一行FETCH NEXT 是唯一支持的提取選項。如果在指定 FORWARD_ONLY 時不指定 STATIC、KEYSET 和 DYNAMIC 關鍵字,則游標作為 DYNAMIC 游標進行操作。如果 FORWARD_ONLY 和 SCROLL 均未指定,則除非指定 STATIC、KEYSET 或 DYNAMIC 關鍵字,否則默認為 FORWARD_ONLY。STATIC、KEYSET 和 DYNAMIC 游標默認為 SCROLL。與 ODBC 和 ADO 這類數據庫 API 不同,STATIC、KEYSET 和 DYNAMIC Transact-SQL 游標支持 FORWARD_ONLY。

SCROLL

     指定所有的提取選項(FIRST、LAST、PRIOR、NEXT、RELATIVE、ABSOLUTE)均可用。如果未在 ISO DECLARE CURSOR 中指定 SCROLL,則 NEXT 是唯一支持的提取選項。如果也指定了 FAST_FORWARD,則不能指定 SCROLL。

declare directionCur cursor --不指定移動方向,則默認為“forward_only”
for
select 學號,姓名 from XSB
Go
open directionCur
fetch next from directionCur
Go
fetch prior from directionCur --錯誤“提取類型 prior 不能與只進游標一起使用。”
Go
close directionCur2
deallocate directionCur2
Go
-----------------------------------------
declare directionCur1 cursor forward_only --指定“forward_only”方向
for
select 學號,姓名 from XSB
Go
open directionCur1
fetch next from directionCur1
Go
fetch prior from directionCur1 --錯誤“提取類型 prior 不能與只進游標一起使用。”
Go
close directionCur2
deallocate directionCur2
Go
-----------------------------------------
declare directionCur2 cursor scroll --指定“scroll”方向
for
select 學號,姓名 from XSB
Go
open directionCur2
fetch next from directionCur2
Go
fetch prior from directionCur2
Go
close directionCur2
deallocate directionCur2
Go
---------------------------------
--結論:若游標沒有指定任何訪問或類型參數,則默認為全局、只進、動態游標。(這是在SQLServer2008 R2上的測試結果,具體取決於軟件設置)

--"scroll"和"fast_forward"不能一起使用
declare forwardTest cursor scroll fast_forward  --報錯“游標選項 SCROLL 和 FAST_FORWARD 沖突。”
for
select 學號,姓名 from XSB
Go

--在 SQL Server 2000 中,FAST_FORWARD 和 FORWARD_ONLY 游標選項是互相排斥的。如果指定了二者,則會引發錯誤。
--在 SQL Server 2005 及更高版本中,這兩個關鍵字可以用在同一個 DECLARE CURSOR 語句中。
declare forwardTest1 cursor forward_only fast_forward
for 
select * from XSB
Go

(4)游標類型

STATIC

     定義一個游標,以創建將由該游標使用的數據的臨時復本。對游標的所有請求都從 tempdb 中的這一臨時表中得到應答;因此,在對該游標進行提取操作時返回的數據中不反映對基表所做的修改,並且該游標不允許修改。及該游標是只讀的。

KEYSET

     指定當游標打開時,游標中行的成員身份和順序已經固定。對行進行唯一標識的鍵集內置在 tempdb 內一個稱為 keyset 的表中。

DYNAMIC

      定義一個游標,以反映在滾動游標時對結果集內的各行所做的所有數據更改。行的數據值、順序和成員身份在每次提取時都會更改。

FAST_FORWARD

      指定啟用了性能優化的 FORWARD_ONLY、READ_ONLY 游標。如果指定了 SCROLL 或 FOR_UPDATE,則不能也指定 FAST_FORWARD。

2、打開游標(OPEN)

語法

OPEN { { [ GLOBAL ] cursor_name } | cursor_variable_name }

示例

--打開游標並讀取所有行
declare XSBcur cursor --聲明
for 
Select * from XSB 
Go
open XSBcur  --打開
fetch next from XSBcur --獲取數據
while @@FETCH_STATUS = 0
begin
fetch next from XSBcur
end
close XSBcur --關閉
deallocate XSBcur --刪除

 全局變量 @@CURSOR_ROWS

該變量保存着最后打開的游標中的數據行數,當其值為0時,表示沒有游標打開;其值為-1時,表示游標為動態的;當其值為-m(m為正整數)時,游標采用異步方式填充,m為當前鍵集中已填充的

行數;當其值為m(m為正整數)時,游標已被完全填充,m是游標中的數據行數。

 3、讀取數據

 語法

FETCH 
          [ [ NEXT | PRIOR | FIRST | LAST 
                    | ABSOLUTE { n | @nvar } 
                    | RELATIVE { n | @nvar } 
               ] 
               FROM 
          ] 
{ { [ GLOBAL ] cursor_name } | @cursor_variable_name } 
[ INTO @variable_name [ ,...n ] ] --into說明將讀取的游標數據存放到指定的變量中

示例

-----------------------------------
declare stuCur cursor scroll
for 
select 學號,姓名 from XSB
GO
open stuCur 
Go
--讀取數據開始
fetch next from stuCur --讀取當前行的下一行,並使其置為當前行(剛開始時游標置於表頭的前一行,即若表是從0開始的,游標最初置於-1處,所以第一次讀取的是頭一行)
fetch prior from stuCur --讀取當前行的前一行,並使其置為當前行
fetch first from stuCur --讀取游標的第一行,並使其置為當前行(不能用於只進游標)
fetch last from stuCur  --讀取游標的最后一行,並使其置為當前行(不能用於只進游標)
fetch absolute 2 from stuCur --讀取從游標頭開始向后的第2行,並將讀取的行作為新的行
fetch relative 3 from stuCur --讀取從當前行開始向后的第3行,並將讀取的行作為新的行
fetch relative-2 from stuCur --讀取當前行的上兩行,並將讀取的行作為新的行
--讀取數據結束
GO
close stuCur 
Go
deallocate stuCur
Go
---------------------------

全局變量 @@FETCH_STATUS

FETCH語句的執行狀態保存在全局變量@@FETCH_STATUS中,其值為0表示上一個FETCH執行成功;為-1表示所要讀取的行不在結果集中;為-2表示被提取的行已不存在(已被刪除)。

4、關閉游標(CLOSE)

 語法

CLOSE { { [ GLOBAL ] cursor_name } | cursor_variable_name }

示例

close stuCur --若該游標事先聲明並已打開
Go

 

5、刪除游標(DEALLOCATE)

對游標進行操作的語句使用游標名稱或游標變量引用游標DEALLOCATE 刪除游標與游標名稱或游標變量之間的關聯如果一個名稱或變量是最后引用游標的名稱或變量,則將釋放游標,游標使用的任何資源也隨之釋放。用於保護提取隔離的滾動鎖在 DEALLOCATE 上釋放。用於保護更新(包括通過游標進行的定位更新)的事務鎖一直到事務結束才釋放。

 語法

DEALLOCATE { { [ GLOBAL ] cursor_name } | @cursor_variable_name }

 示例

游標變量使用下列兩種方法之一與游標關聯:

--聲明一個游標
declare abc cursor scroll 
for
select * from XSB

--(1)通過名稱,使用set語句將游標設置為游標變量
declare @mycur cursor
set @mycur = abc

--(2)也可以不定義游標名稱而創建游標並將其與變量關聯
declare @mycursor cursor
set @mycursor = cursor local scroll for
Select * from XSB

DEALLOCATE @cursor_variable_name 語句只刪除對游標名稱變量的引用。直到批處理、存儲過程或觸發器結束時變量離開作用域,才釋放變量。在 DEALLOCATE @cursor_variable_name 語句之后,可以使用 SET 語句將變量與另一個游標關聯。游標可以理解為指針。

declare @mycur cursor
set @mycur = cursor local scroll for
select * from XSB
 
deallocate @mycur

set @mycur = cursor local scroll for
select * from XSB
GO
--不必顯式釋放游標變量。變量在離開作用域時被隱式釋放。

以下腳本顯示游標如何持續到最后的名稱或持續到引用它們的變量已釋放。

USE AdventureWorks2008R2;
GO
-- Create and open a global named cursor that
-- is visible outside the batch.
DECLARE abc CURSOR GLOBAL SCROLL FOR
SELECT * FROM Sales.SalesPerson;
OPEN abc;
GO
-- Reference the named cursor with a cursor variable.
DECLARE @MyCrsrRef1 CURSOR;
SET @MyCrsrRef1 = abc;
-- Now deallocate the cursor reference.
DEALLOCATE @MyCrsrRef1;
-- Cursor abc still exists.
FETCH NEXT FROM abc;
GO
-- Reference the named cursor again.
DECLARE @MyCrsrRef2 CURSOR;
SET @MyCrsrRef2 = abc;
-- Now deallocate cursor name abc.
DEALLOCATE abc;
-- Cursor still exists, referenced by @MyCrsrRef2.
FETCH NEXT FROM @MyCrsrRef2;
-- Cursor finally is deallocated when last referencing
-- variable goes out of scope at the end of the batch.
GO
-- Create an unnamed cursor.
DECLARE @MyCursor CURSOR;
SET @MyCursor = CURSOR LOCAL SCROLL FOR
SELECT * FROM Sales.SalesTerritory;
-- The following statement deallocates the cursor
-- because no other variables reference it.
DEALLOCATE @MyCursor;
GO

三、用到的數據

1、創建表的腳本

CREATE TABLE [dbo].[XSB](
    [學號] [char](6) NOT NULL,
    [姓名] [char](8) NOT NULL,
    [性別] [bit] NULL,
    [出生時間] [date] NULL,
    [專業] [char](12) NULL,
    [總學分] [int] NULL,
    [備注] [varchar](500) NULL,
PRIMARY KEY CLUSTERED 
(
    [學號] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

2、插入數據

insert into XSB values
('081101','王林','true','1990-2-10','計算機',50,null),
('081102','陳平','true','1991-2-1','計算機',50,null),
('081103','王燕','false','1989-10-6','計算機',50,null),
('081104','韋嚴平','true','1990-8-26','計算機',50,null),
('081106','李芳芳','true','1990-11-20','計算機',50,null),
('081107','李明','true','1990-5-1','計算機',54,'已提前修完數據結構,並獲學分'),
('081108','林一凡','true','1989-8-5','計算機',52,'已提前修完一門課'),
('081109','張強民','true','1989-8-11','計算機',50,null),
('081110','張蔚','false','1991-7-22','計算機',50,'三好生'),
('081111','趙琳','false','1989-10-6','計算機',50,null),
('081113','嚴紅','false','1989-8-11','計算機',48,'一門不及格,待補考'),
('081201','王敏','true','1989-6-10','通信工程',42,null),
('081202','王林','true','1989-6-10','通信工程',40,'一門不及格,待補考')
GO

四、參考資料

 http://technet.microsoft.com/zh-cn/library/ms181441(v=sql.105).aspx


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM