這該死的游標(biāo),怎么這么難呢?
點(diǎn)擊上方SQL數(shù)據(jù)庫開發(fā),關(guān)注獲取SQL視頻教程
SQL專欄
經(jīng)常有小伙伴吐槽SQL中最難的可能就是游標(biāo)了,游標(biāo)確實(shí)不好理解,我們常見的數(shù)據(jù)操作都是返回一個(gè)結(jié)果集,而游標(biāo)則是返回單行記錄。
今天我們就來給小伙伴們講解一下這“該死”的游標(biāo),該如何使用。
1 、什么是游標(biāo)
關(guān)系數(shù)據(jù)庫中的操作會(huì)對(duì)整個(gè)行集起作用。例如,由 SELECT 語句返回的行集包括滿足該語句的 WHERE 子句中條件的所有行。這種由語句返回的完整行集稱為結(jié)果集。應(yīng)用程序,特別是交互式聯(lián)機(jī)應(yīng)用程序,并不總能將整個(gè)結(jié)果集作為一個(gè)單元來有效地處理。這些應(yīng)用程序需要一種機(jī)制以便每次處理一行或一部分行。游標(biāo)就是提供這種機(jī)制的對(duì)結(jié)果集的一種擴(kuò)展。
游標(biāo)通過以下方式來擴(kuò)展結(jié)果處理:
允許定位在結(jié)果集的特定行。
從結(jié)果集的當(dāng)前位置檢索一行或一部分行。
支持對(duì)結(jié)果集中當(dāng)前位置的行進(jìn)行數(shù)據(jù)修改。
為由其他用戶對(duì)顯示在結(jié)果集中的數(shù)據(jù)庫數(shù)據(jù)所做的更改提供不同級(jí)別的可見性支持。
提供腳本、存儲(chǔ)過程和觸發(fā)器中用于訪問結(jié)果集中的數(shù)據(jù)的 Transact-SQL 語句。?
不難理解,游標(biāo)與其他數(shù)據(jù)庫操作的最大不同就是對(duì)象是單條記錄而不是結(jié)果集,一般用于過程化程序里嵌入的SQL語句。在數(shù)據(jù)庫服務(wù)程序里用到了自動(dòng)隱含創(chuàng)建的游標(biāo)。
?
2 、基本用法
2.1 聲明游標(biāo)
DECLARE 游標(biāo)名 CURSOR
FOR SELECT語句
2.2 打開游標(biāo)
OPEN 游標(biāo)名
2.3 從游標(biāo)獲取數(shù)據(jù)
FETCH NEXT | PRIOR | FIRST | LAST |?
?ABSOLUTE{?n| @nvar}?|
RELATIVE?{?n| @nvar}
FROM 游標(biāo)名 [ INTO FETCH_LIST ]
這里要注意的是獲取游標(biāo)里的數(shù)據(jù),除了常用的FETCH NEXT(獲取下一行),SQL Server提供了6種定位選項(xiàng):
緊跟當(dāng)前行返回結(jié)果行,并且當(dāng)前行遞增為返回行。?如果?
FETCH NEXT?為對(duì)游標(biāo)的第一次提取操作,則返回結(jié)果集中的第一行。?NEXT?為默認(rèn)的游標(biāo)提取選項(xiàng)。返回緊鄰當(dāng)前行前面的結(jié)果行,并且當(dāng)前行遞減為返回行。?如果?
FETCH PRIOR?為對(duì)游標(biāo)的第一次提取操作,則沒有行返回并且游標(biāo)置于第一行之前。返回游標(biāo)中的第一行并將其作為當(dāng)前行。
返回游標(biāo)中的最后一行并將其作為當(dāng)前行。
如果 n 或 @nvar 為正,則返回從游標(biāo)起始處開始向后的第 n 行,并將返回行變成新的當(dāng)前行******。?如果 n 或 @nvar 為負(fù),則返回從游標(biāo)末尾處開始向前的第 n 行,并將返回行變成新的當(dāng)前行******。?如果 n 或 @nvar 為 0,則不返回行****。?n 必須是整數(shù)常量,并且 @nvar 必須是 smallint、tinyint 或 int。
如果 n 或 @nvar 為正,則返回從當(dāng)前行開始向后的第 n 行,并將返回行變成新的當(dāng)前行******。?如果 n 或 @nvar 為負(fù),則返回從當(dāng)前行開始向前的第 n 行,并將返回行變成新的當(dāng)前行******。?如果 n 或 @nvar 為 0,則返回當(dāng)前行****。?在對(duì)游標(biāo)進(jìn)行第一次提取時(shí),如果在將 n 或 @nvar 設(shè)置為負(fù)數(shù)或 0 的情況下指定?
FETCH RELATIVE,則不返回行****。?n 必須是整數(shù)常量,并且 @nvar 必須是 smallint、tinyint 或 int。--開始一個(gè)事務(wù)
BEGIN
--定義一個(gè)變量和一個(gè)游標(biāo)
???DECLARE?@custname VARCHAR(20)
???DECLARE?namecursor CURSOR?FOR?
--打開游標(biāo),并從游標(biāo)中獲取數(shù)據(jù),然后插入變量中
?????SELECT?CUST_NAME FROM?TBL_CUSTOMER OPEN?namecursor
???FETCH?NEXT?FROM?namecursor INTO?@custname
--當(dāng)FETCH 語句失敗或此行不在結(jié)果集中時(shí),執(zhí)行下面的IF語句
???WHILE?(@@FETCH_STATUS <> -1)
???BEGIN
--如果被提取的行不存在,執(zhí)行下面的事務(wù)
???????IF?(@@FETCH_STATUS <> -2)
???????BEGIN
???????--操作游標(biāo)變量
???END
???FETCH?NEXT?FROM?namecursor INTO?@custname
END
CLOSE?namecursor
DEALLOCATE?namecursor
END0? ?FETCH 語句成功
-1? FETCH 語句失敗或此行不在結(jié)果集中
-2? 被提取的行不存在
2.4 關(guān)閉游標(biāo)
CLOSE 游標(biāo)名
關(guān)閉后不能對(duì)游標(biāo)進(jìn)行讀取等操作,但可以使用OPEN語句再次打開
2.5 釋放游標(biāo)
DEALLOCATE 游標(biāo)名
即刪除游標(biāo),不可再使用
?
3、游標(biāo)示例

題目要求是:列出從事同一種工作但屬于不同部門的雇員的不同組合
即如下結(jié)果:

在想盡了子查詢、表連接、建臨時(shí)表等等辦法之后,我發(fā)現(xiàn)我遇到了一個(gè)不可逾越的障礙:無法排除兩個(gè)名字組合的唯一性。即:我得到的結(jié)果可能是如下

SELECT A.Ename AS ANAME, B.Ename AS BNAME
INTO #t
FROM EMP A
JOIN EMP B
ON A.job = B.job AND A.deptNo <> B.deptNo and A.Ename<>b.Ename
ORDER BY ANAME
--DROP TABLE #t
DECLARE TEST_CURSOR CURSOR FOR
SELECT ANAME, BNAME FROM #t
OPEN TEST_CURSOR
?DECLARE @ANAME VARCHAR(20)
?DECLARE @BNAME VARCHAR(20)
?FETCH NEXT FROM TEST_CURSOR INTO @ANAME, @BNAME
?DELETE FROM #t WHERE ANAME=@BNAME AND BNAME=@ANAME
?WHILE @@FETCH_STATUS = 0
?BEGIN
? ?FETCH NEXT FROM TEST_CURSOR INTO @ANAME, @BNAME
? ?DELETE FROM #t WHERE ANAME=@BNAME AND BNAME=@ANAME
?END
CLOSE TEST_CURSOR
DEALLOCATE TEST_CURSOR
SELECT * FROM #t以上就是游標(biāo)的一些簡(jiǎn)單介紹,其實(shí)工作中不到萬不得已,一般不會(huì)使用游標(biāo),因?yàn)閷?duì)于數(shù)據(jù)量大的表使用游標(biāo),那執(zhí)行效率絕對(duì)是個(gè)災(zāi)難。
SQL講究的是簡(jiǎn)單才是王道,切勿為了追求什么騷操作把數(shù)據(jù)庫給整垮了,切記!
——End——
后臺(tái)回復(fù)關(guān)鍵字:1024,獲取一份精心整理的技術(shù)干貨 后臺(tái)回復(fù)關(guān)鍵字:進(jìn)群,帶你進(jìn)入高手如云的交流群。 推薦閱讀 這是一個(gè)能學(xué)到技術(shù)的公眾號(hào),歡迎關(guān)注
