SQLServer游标详解
參考資料
http://technet.microsoft.com/zh-cn/library/ms181441(v=sql.105).aspx
一、游標概念
我們知道,關系數據庫所有的關系運算其實是集合與集合的運算,它的輸入是集合輸出同樣是集合,有時需要對結果集逐行進行處理,這時就需要用到游標。我們對游標的使用一本遵循“五步法”:聲明游標—>打開游標—>讀取數據—>關閉游標—>刪除游標。以下就從這五步對游標的使用進行說明,并給出具體實例。
二、“五步法”講解
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
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
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
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 NOT NULL,
[姓名] char NOT NULL,
[性別] [bit] NULL,
[出生時間] [date] NULL,
[專業] char NULL,
[總學分] [int] NULL,
[備注] varchar 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
復制代碼
總結
以上是生活随笔為你收集整理的SQLServer游标详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LabVIEW使用 NI Package
- 下一篇: win7 搭建sip服务器,使用安卓手机