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