T-SQL游标学习总结
生活随笔
收集整理的這篇文章主要介紹了
T-SQL游标学习总结
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
T-SQL查詢進階-10分鐘理解游標
http://www.cnblogs.com/CareySon/archive/2011/11/01/2231381.html 概述在關(guān)系數(shù)據(jù)庫中,我們對于查詢的思考是面向集合的。而游標打破了這一規(guī)則,游標使得我們思考方式變?yōu)橹鹦羞M行.對于類C的開發(fā)人員來著,這樣的思考方式會更加舒服。
正常面向集合的思維方式是:
2
而對于游標來說:
3
這也是為什么游標是邪惡的,它會使開發(fā)人員變懶,懶得去想用面向集合的查詢方式實現(xiàn)某些功能. 同樣的,在性能上,游標會吃更多的內(nèi)存,減少可用的并發(fā),占用寬帶,鎖定資源,當然還有更多的代碼量…… 從游標對數(shù)據(jù)庫的讀取方式來說,不難看出游標為什么占用更多的資源,打個比方:
1
當你從ATM取錢的時候,是一次取1000效率更高呢,還是取10次100? 既然游標這么“邪惡”,為什么還要學習游標
我個人認為存在既是合理.歸結(jié)來說,學習游標原因我歸納為以下2點 1.現(xiàn)存系統(tǒng)有一些游標,我們查詢必須通過游標來實現(xiàn) 2.作為一個備用方式,當我們窮盡了while循環(huán),子查詢,臨時表,表變量,自建函數(shù)或其他方式扔來無法實現(xiàn)某些查詢的時候,使用游標實現(xiàn).
T-SQL中游標的生命周期以及實現(xiàn) 在T-SQL中,游標的生命周期由5部分組成
1.定義一個游標 在T-SQL中,定義一個游標可以是非常簡單,也可以相對復(fù)雜,取決于游標的參數(shù).而游標的參數(shù)設(shè)置取決于你對游標原理的了解程度. 游標其實可以理解成一個定義在特定數(shù)據(jù)集上的指針,我們可以控制這個指針遍歷數(shù)據(jù)集,或者僅僅是指向特定的行,所以游標是定義在以Select開始的數(shù)據(jù)集上的:
4
T-SQL中的游標定義在MSDN中如下: 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變量的定義方法(啥,不知道T-SQL變量定義的規(guī)則?參考我前面的博文).游標變量支持兩種方式賦值,定義時賦值和先定義后賦值,定義游標變量像定義其他局部變量一樣,在游標前加”@”,注意,如果定義全局的游標,只支持定義時直接賦值,并且不能在游標名稱前面加“@”,兩種定義方式如下:
5
下面我們來看游標定義的參數(shù):
LOCAL和GLOBAL二選一 LOCAL意味著游標的生存周期只在批處理或函數(shù)或存儲過程中可見,而GLOBAL意味著游標對于特定連接作為上下文,全局內(nèi)有效,例如:
6
如果不指定游標作用域,默認作用域為GLOBAL
FORWARD_ONLY 和 SCROLL 二選一
FORWARD_ONLY意味著游標只能從數(shù)據(jù)集開始向數(shù)據(jù)集結(jié)束的方向讀取,FETCH NEXT是唯一的選項,而SCROLL支持游標在定義的數(shù)據(jù)集中向任何方向,或任何位置移動,如下圖:
7
STATIC ?KEYSET ?DYNAMIC ?和 FAST_FORWARD 四選一 這四個關(guān)鍵字是游標所在數(shù)據(jù)集所反應(yīng)的表內(nèi)數(shù)據(jù)和游標讀取出的數(shù)據(jù)的關(guān)系 STATIC意味著,當游標被建立時,將會創(chuàng)建FOR后面的SELECT語句所包含數(shù)據(jù)集的副本存入tempdb數(shù)據(jù)庫中,任何對于底層表內(nèi)數(shù)據(jù)的更改不會影響到游標的內(nèi)容. DYNAMIC是和STATIC完全相反的選項,當?shù)讓訑?shù)據(jù)庫更改時,游標的內(nèi)容也隨之得到反映,在下一次fetch中,數(shù)據(jù)內(nèi)容會隨之改變 KEYSET可以理解為介于STATIC和DYNAMIC的折中方案。將游標所在結(jié)果集的唯一能確定每一行的主鍵存入tempdb,當結(jié)果集中任何行改變或者刪除時,@@FETCH_STATUS會為-2,KEYSET無法探測新加入的數(shù)據(jù)
FAST_FORWARD可以理解成FORWARD_ONLY的優(yōu)化版本.FORWARD_ONLY執(zhí)行的是靜態(tài)計劃,而FAST_FORWARD是根據(jù)情況進行選擇采用動態(tài)計劃還是靜態(tài)計劃,大多數(shù)情況下FAST_FORWARD要比FORWARD_ONLY性能略好.
READ_ONLY ?SCROLL_LOCKS ?OPTIMISTIC 三選一? READ_ONLY意味著聲明的游標只能讀取數(shù)據(jù),游標不能做任何更新操作
SCROLL_LOCKS是另一種極端,將讀入游標的所有數(shù)據(jù)進行鎖定,防止其他程序進行更改,以確保更新的絕對成功
OPTIMISTIC是相對比較好的一個選擇,OPTIMISTIC不鎖定任何數(shù)據(jù),當需要在游標中更新數(shù)據(jù)時,如果底層表數(shù)據(jù)更新,則游標內(nèi)數(shù)據(jù)更新不成功,如果,底層表數(shù)據(jù)未更新,則游標內(nèi)表數(shù)據(jù)可以更新
2.打開游標
當定義完游標后,游標需要打開后使用,只有簡單一行代碼:
OPEN test_Cursor 注意,當全局游標和局部游標變量重名時,默認會打開局部變量游標
3.使用游標 游標的使用分為兩部分,一部分是操作游標在數(shù)據(jù)集內(nèi)的指向,另一部分是將游標所指向的行的部分或全部內(nèi)容進行操作 只有支持6種移動選項,分別為到第一行(FIRST),最后一行(LAST),下一行(NEXT),上一行(PRIOR),直接跳到某行(ABSOLUTE(n)),相對于目前跳幾行(RELATIVE(n)),例如:
8
對于未指定SCROLL選項的游標來說,只支持NEXT取值. 第一步操作完成后,就通過INTO關(guān)鍵字將這行的值傳入局部變量:
比如下面代碼:
10
9
游標經(jīng)常會和全局變量@@FETCH_STATUS與WHILE循環(huán)來共同使用,以達到遍歷游標所在數(shù)據(jù)集的目的,例如:
11
4.關(guān)閉游標
在游標使用完之后,一定要記得關(guān)閉,只需要一行代碼:CLOSE+游標名稱
CLOSE test_Cursor 5.釋放游標
當游標不再需要被使用后,釋放游標,只需要一行代碼:DEALLOCATE+游標名稱
DEALLOCATE test_Cursor 對于游標一些優(yōu)化建議
如果能不用游標,盡量不要使用游標 用完用完之后一定要關(guān)閉和釋放 盡量不要在大量數(shù)據(jù)上定義游標 盡量不要使用游標上更新數(shù)據(jù) 盡量不要使用insensitive, static和keyset這些參數(shù)定義游標 如果可以,盡量使用FAST_FORWARD關(guān)鍵字定義游標 如果只對數(shù)據(jù)進行讀取,當讀取時只用到FETCH NEXT選項,則最好使用FORWARD_ONLY參數(shù) 總結(jié)
本文從游標的基本概念,到生命周期來談游標。游標是非常邪惡的一種存在,使用游標經(jīng)常會比使用面向集合的方法慢2-3倍,當游標定義在大數(shù)據(jù)量時,這個比例還會增加。如果可能,盡量使用while,子查詢,臨時表,函數(shù),表變量等來替代游標,記住,游標永遠只是你最后無奈之下的選擇,而不是首選。 ========
T-SQL游標使用
http://blog.csdn.net/ht_927/article/details/6006778 ?使用游標(cursor) 的一個主要的原因就是把集合操作轉(zhuǎn)換成單個記錄處理方式。用 SQL 語言從數(shù)據(jù)庫中檢索數(shù)據(jù)后,結(jié)果放在內(nèi)存的一塊區(qū)域中, 且結(jié)果往往是一個含有多個記錄的集合。游標機制允許用戶在 SQL server 內(nèi)逐行地訪問這些記錄,按照用戶自己的意愿來顯示和處理這些記錄。 1. 為何使用游標: 使用游標 (cursor) 的一個主要的原因就是把集合操作轉(zhuǎn)換成單個記錄處理方式。用 SQL 語言從數(shù)據(jù)庫中檢索數(shù)據(jù)后,結(jié)果放在內(nèi)存的一塊區(qū)域中,且結(jié)果往往是一個含有多個記錄的集合。游標機制允許用戶在 SQL server 內(nèi)逐行地訪問這些記錄,按照用戶自己的意愿來顯示和處理這些記錄。 2. 如何使用游標: 一般地,使用游標都遵循下列的常規(guī)步驟: (1) ?聲明游標。把游標與 T-SQL 語句的結(jié)果集聯(lián)系起來。? (2) ?打開游標。? (3) ?使用游標操作數(shù)據(jù)。? (4) ?關(guān)閉游標。 2.1. 聲明游標 DECLARE CURSOR 語句 SQL-92 標準語法格式: DECLARE 游標名 [ INSENSITIVE ] [ SCROLL ] CURSOR FOR ? sql-statement Eg: Declare MycrsrVar Cursor FOR Select * FROM tbMyData 2.2 ?打開游標 OPEN MycrsrVar 當游標被打開時,行指針將指向該游標集第 1 行之前,如果要讀取游標集中的第 1 行數(shù)據(jù),必須移動行指針使其指向第 1 行。就本例而言,可以使用下列操作讀取第 1 行數(shù)據(jù): FETCH FIRST from E1cursor 或 FETCH NEXT from E1cursor 2.3 ? ? ?使用游標操作數(shù)據(jù) ? ? 下面的示例用 @@FETCH_STATUS 控制在一個 WHILE 循環(huán)中的游標活動 /* 使用游標讀取數(shù)據(jù)的操作如下。 */ DECLARE E1cursor cursor /* 聲明游標,默認為 FORWARD_ONLY 游標 */ FOR SELECT * FROM c_example OPEN E1cursor /* 打開游標 */ FETCH NEXT from E1cursor /* 讀取第 1 行數(shù)據(jù) */ WHILE @@FETCH_STATUS = 0 /* 用 WHILE 循環(huán)控制游標活動 */ BEGINFETCH NEXT from E1cursor /* 在循環(huán)體內(nèi)將讀取其余行數(shù)據(jù) */ END CLOSE E1cursor /* 關(guān)閉游標 */ DEALLOCATE E1cursor /* 刪除游標 */
2.4 ? ?關(guān)閉游標 使用CLOSE 語句關(guān)閉游標 CLOSE { { [ GLOBAL ]游標名 ?} | 游標變量名 ?} 使用DEALLOCATE 語句刪除游標,其語法格式如下: DEALLOCATE { { [ GLOBAL ]游標名 ?} | @ 游標變量名? 3. FETCH操作的簡明語法如下: FETCH [ NEXT | PRIOR | FIRST | LAST] FROM {游標名 ?| @ 游標變量名 ?} [ INTO @ 變量名 ?[ , …] ] 參數(shù)說明: NEXT ?取下一行的數(shù)據(jù),并把下一行作為當前行 ( 遞增 ) 。由于打開游標后,行指針是指向該游標第 1 行之前,所以第一次執(zhí)行 FETCH NEXT 操作將取得游標集中的第 1 行數(shù)據(jù)。 NEXT 為默認的游標提取選項。 INTO @變量名 [,…] ?把提取操作的列數(shù)據(jù)放到局部變量中。列表中的各個變量從左到右與游標結(jié)果集中的相應(yīng)列相關(guān)聯(lián)。各變量的數(shù)據(jù)類型必須與相應(yīng)的結(jié)果列的數(shù)據(jù)類型匹配或是結(jié)果列數(shù)據(jù)類型所支持的隱性轉(zhuǎn)換。變量的數(shù)目必須與游標選擇列表中的列的數(shù)目一致。 -------------------------------------------------------------------------------------------------------------------------------- 每執(zhí)行一個FETCH 操作之后,通常都要查看一下全局變量 @@FETCH_STATUS 中的狀態(tài)值,以此判斷 FETCH 操作是否成功。該變量有三種狀態(tài)值: · 0 表示成功執(zhí)行 FETCH 語句。 · -1 表示 FETCH 語句失敗,例如移動行指針使其超出了結(jié)果集。 · -2 表示被提取的行不存在。 由于@@FETCH_STATU 是全局變量,在一個連接上的所有游標都可能影響該變量的值。因此,在執(zhí)行一條 FETCH 語句后,必須在對另一游標執(zhí)行另一 FETCH 語句之前測試該變量的值才能作出正確的判斷。?
--示例? declare @Familyid int declare @address nvarchar(100) DECLARE E1cursor cursor /* 聲明游標,默認為 FORWARD_ONLY 游標 */ FOR SELECT address FROM FamilyInfo where Family_id<10 OPEN E1cursor /* 打開游標 */ FETCH NEXT from E1cursor into @address /* 讀取第 1 行數(shù)據(jù) */ WHILE @@FETCH_STATUS = 0 /* 用 WHILE 循環(huán)控制游標活動 */ BEGIN SELECT * FROM mHUB_fnSplit(@address,'%') where @@rowcount<4 FETCH NEXT from E1cursor into @address /*讀取其它記錄 */ END CLOSE E1cursor DEALLOCATE E1cursor
========
SQL Server游標
http://www.cnblogs.com/knowledgesea/p/3699851.html 什么是游標 結(jié)果集,結(jié)果集就是select查詢之后返回的所有行數(shù)據(jù)的集合。游標則是處理結(jié)果集的一種機制吧,它可以定位到結(jié)果集中的某一行,多數(shù)據(jù)進行讀寫,也可以移動游標定位到你所需要的行中進行操作數(shù)據(jù)。
一般復(fù)雜的存儲過程,都會有游標的出現(xiàn),他的用處主要有:
定位到結(jié)果集中的某一行。 對當前位置的數(shù)據(jù)進行讀寫。 可以對結(jié)果集中的數(shù)據(jù)單獨操作,而不是整行執(zhí)行相同的操作。 是面向集合的數(shù)據(jù)庫管理系統(tǒng)和面向行的程序設(shè)計之間的橋梁。 游標的分類 根據(jù)游標檢測結(jié)果集變化的能力和消耗資源的情況不同,SQL Server支持的API服務(wù)器游標分為一下4種:
靜態(tài)游標: 靜態(tài)游標的結(jié)果集,在游標打開的時候建立在TempDB中,不論你在操作游標的時候,如何操作數(shù)據(jù)庫,游標中的數(shù)據(jù)集都不會變。例如你在游標打開的時候,對游標查詢的數(shù)據(jù)表數(shù)據(jù)進行增刪改,操作之后,靜態(tài)游標中select的數(shù)據(jù)依舊顯示的為沒有操作之前的數(shù)據(jù)。如果想與操作之后的數(shù)據(jù)一致,則重新關(guān)閉打開游標即可。 動態(tài)游標:這個則與靜態(tài)游標相對,滾動游標時,動態(tài)游標反應(yīng)結(jié)果集中的所有更改。結(jié)果集中的行數(shù)據(jù)值、順序和成員在每次提取時都會變化。所有用戶做的增刪改語句通過游標均可見。如果使用API函數(shù)或T-SQL Where Current of子句通過游標進行更新,他們將立即可見。在游標外部所做的更新直到提交時才可見。 只進游標:只進游標不支持滾動,只支持從頭到尾順序提取數(shù)據(jù),數(shù)據(jù)庫執(zhí)行增刪改,在提取時是可見的,但由于該游標只能進不能向后滾動,所以在行提取后對行做增刪改是不可見的。 鍵集驅(qū)動游標:打開鍵集驅(qū)動游標時,該有表中的各個成員身份和順序是固定的。打開游標時,結(jié)果集這些行數(shù)據(jù)被一組唯一標識符標識,被標識的列做刪改時,用戶滾動游標是可見的,如果沒被標識的列增該,則不可見,比如insert一條數(shù)據(jù),是不可見的,若可見,須關(guān)閉重新打開游標。 靜態(tài)游標在滾動時檢測不到表數(shù)據(jù)變化,但消耗的資源相對很少。動態(tài)游標在滾動時能檢測到所有表數(shù)據(jù)變化,但消耗的資源卻較多。鍵集驅(qū)動游標則處于他們中間,所以根據(jù)需求建立適合自己的游標,避免資源浪費。。
游標的生命周期 游標的生命周期包含有五個階段:聲明游標、打開游標、讀取游標數(shù)據(jù)、關(guān)閉游標、釋放游標。
1.聲明游標,語法
復(fù)制代碼 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 ] ] ]
復(fù)制代碼 參數(shù)說明:
cursor_name:游標名稱。 Local:作用域為局部,只在定義它的批處理,存儲過程或觸發(fā)器中有效。 Global:作用域為全局,由連接執(zhí)行的任何存儲過程或批處理中,都可以引用該游標。 [Local | Global]:默認為local。 Forward_Only:指定游標智能從第一行滾到最后一行。Fetch Next是唯一支持的提取選項。如果在指定Forward_Only是不指定Static、KeySet、Dynamic關(guān)鍵字,默認為Dynamic游標。如果Forward_Only和Scroll沒有指定,Static、KeySet、Dynamic游標默認為Scroll,Fast_Forward默認為Forward_Only Static:靜態(tài)游標 KeySet:鍵集游標 Dynamic:動態(tài)游標,不支持Absolute提取選項 Fast_Forward:指定啟用了性能優(yōu)化的Forward_Only、Read_Only游標。如果指定啦Scroll或For_Update,就不能指定他啦。 Read_Only:不能通過游標對數(shù)據(jù)進行刪改。 Scroll_Locks:將行讀入游標是,鎖定這些行,確保刪除或更新一定會成功。如果指定啦Fast_Forward或Static,就不能指定他啦。 Optimistic:指定如果行自讀入游標以來已得到更新,則通過游標進行的定位更新或定位刪除不成功。當將行讀入游標時,sqlserver不鎖定行,它改用timestamp列值的比較結(jié)果來確定行讀入游標后是否發(fā)生了修改,如果表不行timestamp列,它改用校驗和值進行確定。如果已修改改行,則嘗試進行的定位更新或刪除將失敗。如果指定啦Fast_Forward,則不能指定他。 Type_Warning:指定將游標從所請求的類型隱式轉(zhuǎn)換為另一種類型時向客戶端發(fā)送警告信息。 For Update[of column_name ,....] :定義游標中可更新的列。 2.聲明一個動態(tài)游標
declare orderNum_02_cursor cursor scroll for select OrderId from bigorder where orderNum='ZEORD003402' 3.打開游標
--打開游標語法 open [ Global ] cursor_name | cursor_variable_name cursor_name:游標名,cursor_variable_name:游標變量名稱,該變量引用了一個游標。
--打開游標 open orderNum_02_cursor 4.提取數(shù)據(jù)
復(fù)制代碼 --提取游標語法 Fetch [ [Next|prior|Frist|Last|Absoute n|Relative n ] from ] [Global] cursor_name [into @variable_name[,....]] 復(fù)制代碼 參數(shù)說明:
Frist:結(jié)果集的第一行 Prior:當前位置的上一行 Next:當前位置的下一行 Last:最后一行 Absoute n:從游標的第一行開始數(shù),第n行。 Relative n:從當前位置數(shù),第n行。 Into @variable_name[,...] : 將提取到的數(shù)據(jù)存放到變量variable_name中。 例子:
復(fù)制代碼 --提取數(shù)據(jù) fetch first from orderNum_02_cursor fetch relative 3 from orderNum_02_cursor fetch next from orderNum_02_cursor fetch absolute 4 from orderNum_02_cursor fetch next from orderNum_02_cursor fetch last from orderNum_02_cursor? fetch prior from orderNum_02_cursor select * from bigorder where orderNum='ZEORD003402' 復(fù)制代碼 結(jié)果(對比一下,就明白啦):
例子:
--提取數(shù)據(jù)賦值給變量 declare @OrderId int fetch absolute 3 from orderNum_02_cursor into @OrderId select @OrderId as id select * from bigorder where orderNum='ZEORD003402' 結(jié)果:
通過檢測全局變量@@Fetch_Status的值,獲得提取狀態(tài)信息,該狀態(tài)用于判斷Fetch語句返回數(shù)據(jù)的有效性。當執(zhí)行一條Fetch語句之后,@@Fetch_Status可能出現(xiàn)3種值:0,Fetch語句成功。-1:Fetch語句失敗或行不在結(jié)果集中。-2:提取的行不存在。
這個狀態(tài)值可以幫你判斷提取數(shù)據(jù)的成功與否。
復(fù)制代碼 declare @OrderId int fetch absolute 3 from orderNum_02_cursor into @OrderId while @@fetch_status=0 ?--提取成功,進行下一條數(shù)據(jù)的提取操作 begin select @OrderId as id fetch ?next from orderNum_02_cursor into @OrderId ?--移動游標 end? 復(fù)制代碼 5.利用游標更新刪除數(shù)據(jù)?
--游標修改當前數(shù)據(jù)語法 Update 基表名 Set 列名=值[,...] Where Current of 游標名 --游標刪除當前數(shù)據(jù)語法 Delete 基表名 ?Where Current of 游標名 復(fù)制代碼 ---游標更新刪除當前數(shù)據(jù) ---1.聲明游標 declare orderNum_03_cursor cursor scroll for select OrderId ,userId from bigorder where orderNum='ZEORD003402' --2.打開游標 open orderNum_03_cursor --3.聲明游標提取數(shù)據(jù)所要存放的變量 declare @OrderId int ,@userId varchar(15) --4.定位游標到哪一行 fetch First from orderNum_03_cursor into @OrderId,@userId --into的變量數(shù)量必須與游標查詢結(jié)果集的列數(shù)相同 while @@fetch_status=0 --提取成功,進行下一條數(shù)據(jù)的提取操作 beginif @OrderId=122182beginUpdate bigorder Set UserId='123' Where Current of orderNum_03_cursor --修改當前行endif @OrderId=154074beginDelete bigorder Where Current of orderNum_03_cursor --刪除當前行endfetch next from orderNum_03_cursor into @OrderId ,@userId --移動游標end
6.關(guān)閉游標
游標打開后,服務(wù)器會專門為游標分配一定的內(nèi)存空間存放游標操作的數(shù)據(jù)結(jié)果集,同時使用游標也會對某些數(shù)據(jù)進行封鎖。所以游標一旦用過,應(yīng)及時關(guān)閉,避免服務(wù)器資源浪費。
--關(guān)閉游標語法 close [ Global ] cursor_name | cursor_variable_name --關(guān)閉游標 close orderNum_03_cursor 7.刪除游標
刪除游標,釋放資源
--釋放游標語法 deallocate ?[ Global ] cursor_name | cursor_variable_name --釋放游標 deallocate orderNum_03_cursor ========
T-SQL 游標 游標更新數(shù)據(jù)
http://blog.sina.com.cn/s/blog_56294d0a0101fj77.html 游標的引入 1 .在數(shù)據(jù)的開發(fā)過程中,從某一結(jié)果集中逐一讀取一條記錄,用游標解決,游標占資源大,確定不用后將其釋放。 2 .聲明游標(四個組成部分) ( 1 ).declare游標 ( 2 ).open游標 ( 3 ).從一個游標中fetch信息 ( 4 ).close或deallocate游標 一、聲明游標主要內(nèi)容: ( 1 ).游標名字 ( 2 ).數(shù)據(jù)來源表和列 ( 3 ).選取條件 ( 4 ).屬性僅讀或可修改 1 .語法格式: declare ?游標名稱 ?[ scroll ] ? cursor? [ local|global ]? [ forward_only|scroll ]? for ?選擇語句 [ for[read_only|update [of 字段名稱1,字段名稱2, ] ]] 其中: 1 > .local | global指定該游標的作用域是局部的還是全局的。 2 > .如果把forward_only選擇為forward_only, 則游標只能從第一行滾動到最后一行。 3 > .scroll表明所有的提取操作,如first,last,prior, next ,relative,absolute都可用。如不使用該保留字,那么只能進行next提取操作。 4 > .選擇語句:是定義結(jié)果集的select語句,應(yīng)該注意的是在游標中不能使用compute, compute ? by ? for ?browse ?into語句. 5 > . read ? only :表明不允許游標內(nèi)的數(shù)據(jù)被更新。 6 > . update [ of 字段名1[, n ] ]:定義在游標中可被修改的列。 例1:標準游標 declare taihang cursor for select id,name,address,city,statefrom table例2:只讀游標 declare taihang cursor for select id,name,address,city,atatefrom table for read only
例3:更新游標 declare taihang cursor for select name,addressfrom table for update
? 二、打開游標 1 .聲明之后,如要從游標中讀取數(shù)據(jù),必須打開游標,使用open命令。 語法: open 游標名稱 注意: 1 > .在打開游標時,如果游標聲明語句中使用了insensitive保留字,則open產(chǎn)生一個臨時表來存放結(jié)果集。如果在結(jié)果集中任何一行數(shù)據(jù)的大小超過SQL Server定義的最大行尺寸時,open命令將失敗。 2 > .insensitive: 表明SQL Server會將游標定義所選取出來的數(shù)據(jù)記錄存放在一臨時表內(nèi),(建立在tempdb數(shù)據(jù)庫下)對該游標的操作皆由臨時表來應(yīng)答。因此,對 基本表的修改并不影響游標提取數(shù)據(jù),即游標不會隨著基本表內(nèi)容的改變面改變,同時也不法通過游標來更新基本表。 如果不使用該保留字,那么對基本表的更新,刪除都會公映到游標中。 三、讀取游標中的數(shù)據(jù)- fetch? 1 .當游標被成功打開以后就可以從游標中逐行地讀取數(shù)據(jù)以時行相關(guān)處理。從游標中讀取數(shù)據(jù)主要使用fetch命令。 語法: fetch? [ [next|prior|first|last |absolute{n|@nvar} |relative{n|@nvar} ]? from ] cursor_name [ into @variable_name1,@variable_name2 ]? 注: 1 > . next :返回結(jié)果集中當前行的下一行,并增加當前行數(shù)為返回行行數(shù)。如果fetch next是第一次讀取游標中數(shù)據(jù),則返回結(jié)果集中的第一行而不是第二行。 2 > .prior:返回結(jié)果集中當前行的前一行,并減少當前行數(shù)為返回行行數(shù)。如果fetch prior是第一次讀取游標中的數(shù)據(jù),剛無數(shù)據(jù)記錄返回,并把游標位置設(shè)為第一行。 3 > .first:返回游標中的第一行。 4 > .last:返回游標中的最后一行。 5 > .absolute{n | @nvar }:如果N或 @nvar為正數(shù) ,則表示從游標中返回的數(shù)據(jù)行數(shù)。如果N或 @nvar為負數(shù),則返回游標內(nèi)從最后一行數(shù)據(jù)算起的第N或 @nvar行數(shù)據(jù) 。若N或 @nvar超過游標的數(shù)據(jù)子集范疇 ,則@@fetch_status返回 - 1 。在該情況下,如果N或 @nvar為負數(shù) ,則再執(zhí)行fetch next命令會得到第一行數(shù)據(jù);如果N或 @nvar為正值 ,如執(zhí)行fetch prior命令剛會得到最后一行數(shù)據(jù)。N或 @nvar可以是固定值 ,也可以是smallint,tinyint或int類型的變量。 6 > .relative{N | @nvar }:若N或 @nvar為正數(shù) ,則讀取游標當前位置起向后的第N或 @nvar行數(shù)據(jù) 。如果N或@nvar為負數(shù) ,則返回游標當前位置起向前的第N或 @nvar行數(shù)據(jù) 。若N或 @nvar超過游標的數(shù)據(jù)子集范疇 ,則 @@fetch_status返回 - 1 。在該情況下,如果N或 @nvar為負數(shù) ,則再執(zhí)行fetch next命令會得到第一行數(shù)據(jù);如果N或 @nvar為正值 ,如執(zhí)行fetch prior命令剛會得到最后一行數(shù)據(jù)。N或 @nvar可以是固定值 ,也可以是smallint,tinyint或int類型的變量。 7 > . into @variable_name [ , n ] :允許使用fetch命令讀取的數(shù)據(jù)存放在多個變量中;在變量行中的每個變量必須與游標結(jié)果集中相應(yīng)的列相對應(yīng),每一變量的數(shù)據(jù)類型也要與游標中的數(shù)據(jù)列的數(shù)據(jù)類型相匹配。 2 .檢查游標狀態(tài) @@fetch_status :全局變量,返回上次執(zhí)行fetch命令的狀態(tài),在每次用fetch從游標中讀取數(shù)據(jù)時,都應(yīng)檢查該變量以確定上次fetch操作是否成功,來決定如何進行下一步處理。 @@fetch_status變量有三個不同返回值。 1 > . 0 :表示成功取出了一行。 2 > . - 1表示未取到數(shù)據(jù)。游標位置超出結(jié)果集。 3 > . - 2表示返回的行已經(jīng)不再是結(jié)果集的一個成員,這種情況只有在游標不是insensitive的情況下出現(xiàn),即其它進程已刪除了行或改變了游標打開的關(guān)鍵值。 3 .編輯當前游標行 通 常,用游標來從基礎(chǔ)表中檢索數(shù)據(jù),以實現(xiàn)對數(shù)據(jù)行處理,在修改游標中的數(shù)據(jù),即進行定位更新或刪除游標所包含的數(shù)據(jù),所以必須執(zhí)行另外的更新或刪除命令, 并在where子句中重新給定條件才能修改到該行數(shù)據(jù),但是如果在聲明游標時使用了for update語句那么就可以在update或delete命令 中以where ?current ?of關(guān)鍵字直接修改或刪除當前游標中所存儲的數(shù)據(jù),而不必使用where子句重新給出指定條件。當改變游標中數(shù)據(jù)時,這種變化會自動地影響到游標的基礎(chǔ)表。但是如果在聲明游標時選擇了insensitive選項時,該游標中的數(shù)據(jù)不能被修改。 進行定位修改或刪除游標中的數(shù)據(jù)的語法規(guī)則語法: update ?table_name set ?column_name1 = {expression1 | null (select_statement)} [ ,column_name2={expression2|null(select_statement)} ]? where ? current ? of ?cursor_name delete ? from ?table_name where ? current ? of ?cursor_name 其中: 1 > .table_name:是update或delete的表名。 2 > .column_name:uqdate的列名 3 > .cursor_name:游標名 例1:首先聲明一個游標 declare authors_cur scroll cursor for select * from authorsfor update of au_lname,au_fname 更新authors表中的au_lname和au_fname列 update authorsset au_lname = ' china ' ,au_fname = ' asia ' where current of authors_cur 刪除authors表中的一行數(shù)據(jù) delete ? from ?authors where ? current ? of ?authors_cur 注:以上的更新或刪除操作總是在游標的當前位置, 例:下面是一個完整的定位更新的例子。 declare @au_id int ( 11 ), @au_lname varchar ( 40 ), @au_fname varchar ( 20 )declare authors_cur cursor for select au_id,au_lname,au_fname from authorsfor update of au_id,aulname,au_fnameopen authors_cur fetch next from authors_cer into @au_id , @au_lname , @au_fname while @@fetch_status = 0 begin if @au_id = ' 172-32-1176 ' update authorsset au_lname = ' smith ' ,au_fname = ' jake ' where current of authors_curfetch next from authors_cer into @au_id , @au_lname , @au_fname end deallocate authors_cur
四、釋放游標 1 .關(guān)閉游標 使用close命令關(guān)閉游標,在處理完游標中數(shù)據(jù)之后,發(fā)布關(guān)閉游標來釋放數(shù)據(jù)結(jié)果集和定位于數(shù)據(jù)記錄上的鎖,close語句關(guān)閉游標但不釋放游標占用的數(shù)據(jù)結(jié)構(gòu)。如果準備在隨后的使用中再次打開游標,則應(yīng)使用open命令。 語法: close ?游標名稱 2 .釋放游標 在使用游標時各種針對游標的操作或者引用游標各或者引用指向游標的游標變量,當close命令關(guān)閉游標時并沒有釋放游標占用的數(shù)據(jù)結(jié)構(gòu)。因此常使用deallocate命令刪除掉游標與游標名或游標變量之間的聯(lián)系,并且釋放游標占用的所有系統(tǒng)資源。 語法: deallocate ?游標名稱 ========
請問怎么用T-sql實現(xiàn)游標的遞歸
好象TSQL里面游標是個全局變量 有沒有其他方法可以解決啊
可以借助存儲過程的遞歸,在存儲過程內(nèi)部使用LOCAL聲明游標為局部游標。
create ? ? FUNCTION ? dbo.GetSubClass(@Code_No ? varchar(50),@IdStr ? varchar(8000)='',@LevelCount ? int=-1) ? ?? /* ?? 參數(shù): @Code_No ? ,被搜索子類的ID ?? @IdStr,一個特殊參數(shù),用于在遞歸中傳數(shù)據(jù),注意:調(diào)用函數(shù)時一定要傳入‘’空值 ?? @LevelCount ? 用于判斷是不是遞歸調(diào)用的最上層 ?? */ ?? RETURNS ? Varchar(8000) ?? AS ? ? ?? BEGIN ? ?? Declare ? @single_no ? varchar(50), ? @TC_ID ? varchar(50),@TC_PID ? Varchar(50),@StartLevel ? int,@Id32 ? int,@Ma_price ? Numeric(19,3) ?? if ? @LevelCount=-1 ?? begin ?? set ? @StartLevel=@@NESTLEVEL ?? set ? @LevelCount=@StartLevel ?? end ?? else ? ?? set ? @StartLevel=-1 ?? If ? @IdStr='' ? Set ?? @IdStr=''''+@InputId ? +'''' ?? DECLARE ? TreeClass ? CURSOR ? local ? FOR ? --定義游標 ?? Select ? b.single_no,b.Code_No ? From ? Mrp_Modec ? a ? ,Mrp_Mode ? b ? where ? a.single_no=b.single_no ? and ? In_Code= ? @InputId ?? OPEN ? TreeClass ?? FETCH ? NEXT ? FROM ? TreeClass ?? INTO ? @single_no,@TC_ID ?? WHILE ? @@FETCH_STATUS ? = ? 0 --循環(huán)游標,即循環(huán)當前類的弟一級子類 ?? BEGIN ?? if ? ? ? ? exists(select ? * ? from ? mrp_modec ? ? ) ? ?? select ? @Ma_price=Sum(sta_qty*u_price) ? from ? ? ? Mrp_Modec ? Where ? ? ? single_no=@single_no ? ? ?? update ? 表名 ? SET ? 字段= ? @Ma_price ? WHERE ? ? ? single_no=@single_no ? ? --這里為什么通不過 ?? select ? @IdStr= ? @IdStr+','+cast(@tC_ID ? as ? varchar)+'''' ?? if ? @@NESTLEVEL<32 ?? set ? @IdStr= ? dbo.GetSubClass(@TC_ID,@IdStr,@LevelCount) ? --遞歸。 ?? else ?? set ? @IdStr='['+cast(@tC_ID ? as ? varchar)+']'+@IdStr ?? FETCH ? NEXT ? FROM ? TreeClass ? iNTO ? @single_no,@tC_ID ? ?? End ?? CLOSE ? TreeClass ?? DEALLOCATE ? TreeClass ?? /*while ? @StartLevel=@@NESTLEVEL ? and ? charindex(']',@IdStr)>0 ?? begin ?? set ? @Id32=substring(@IdStr,2,charindex(']',@IdStr)-2) ?? set ? @IdStr=dbo.FN_32GetSubClass ? (@Id32,@IdStr,@LevelCount) ?? set ? @IdStr=replace(@IdStr,'['+cast(@Id32 ? as ? varchar)+']','') ?? end ?? */ ?? Return ? ? @IdStr ?? END ?? 但是我還要輸出游標啊? 得到一個結(jié)果集 對這個結(jié)果集在操作 其中要用到遞歸
樓主參考一下: http://community.csdn.net/Expert/topic/4896/4896332.xml?temp=.569317
游標默認定義是global
用下面的定義就可以了
declare 游標名 CURSOR LOCAL ?-- LOCAL指定游標為局部的(默認是GLOBAL, 全局的) FOR
但是遞歸怎么辦啊? 輸出參數(shù)為游標 ========
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的T-SQL游标学习总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VS调试js学习总结
- 下一篇: CSS居中学习总结