# MsSql Cursor應用
###### tags: `MSSQL` , `連猴子也能懂系列`
>參考文件:https://docs.microsoft.com/zh-tw/sql/t-sql/language-elements/declare-cursor-transact-sql?view=sql-server-ver15
1.語法
===
DECLARE CURSOR 子句
```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 ] ] ]
```
---
2.引數
===
2.1 游標有效範圍:**LOCAL** | GLOBAL
* LOCAL:區域游標表示該游標只在這個範圍內有效。
* GLOBAL:全域游標表示該游標可以在同一個 connection 下的所有 sp 或 batch 中共用。
2.2 游標讀取方式:**FORWARD_ONLY** | SCROLL
* **FORWARD_ONLY**:游標只可以順向讀取( FETCH NEXT )。
* SCROLL:這個項選表示可以使用所有 FETCH 功能:
-FETCH FIRST:位置跳到 第一筆
-FETCH LAST:位置跳到 最後一筆
-**FETCH NEXT**:位置跳到 下一筆
-FETCH PRIOR:位置跳到 上一筆
-FETCH ABSOLUTE n:位置跳到 第n行
-FETCH RELATIVE n:當前位置開始的第n行
2.3 游標型態:STATIC | KEYSET | DYNAMIC | **FAST_FORWARD**
* STATIC:靜態資料指標,唯讀,且無法得知其他使用者的變更。
* KEYSET:索引鍵集資料指標,使用索引值關連到來源資料表中的實際資料。
* DYNAMIC:動態資料指標。
* **FAST_FORWARD**:效能最佳化,這種資料指標類型不允許從資料指標內部修改資料。使用 FAST_FORWARD 等同使用 FORWARD_ONLY + READ_ONLY
2.4 Concurrency Options
* READ_ONLY:唯讀游標,不鎖定。
* SCROLL_LOCKS:當資料列讀入資料游標時,SQL Server 會立即鎖定這些資料列,以確保之後可對它們進行修改。
* OPTIMISTIC:不鎖定。原始資料中之記錄若已被異動,再由Cursor去異動該筆記錄時會導致失敗。
---
3.提取狀態 - @@FETCH_STATUS
===
* 0: 提取成功
* -1: 提取失敗
* -2: 要獲取之記錄已不存在
---
4.建議用法
===
Carey大大建議使用==FAST_FORWARD==,避免影響效能
大致流程:
```flow
st=>start: 開始
e=>end: 結束
op1=>operation: 將table資料寫入Cursor
op2=>operation:
cond1=>condition: 迴圈(抓值成功)
Fetch == 0 ?
s1=>subroutine: Do something
s2=>subroutine: Fetch next from Cursor
st->op1->cond1
cond1(yes, right)->s1->s2(right)->cond1
cond1(no, left)->e
```
範例:
```sql=
--宣告游標需要用到的參數
DECLARE @TableName VARCHAR(128) --table 名稱
--建立Cursor, 取得需要Switch Table 清單
DECLARE TableCursor CURSOR LOCAL FAST_FORWARD FOR
SELECT TableName
FROM MoveToHistoryTableName
--迴圈執行每一筆
OPEN TableCursor
FETCH NEXT FROM TableCursor INTO @TableName; --擷取游標內容
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'table name: ' + @TableName; --印出表名稱
--(do something)
--next
FETCH NEXT FROM TableCursor INTO @TableName;
END;
--close cursor
CLOSE TableCursor;
DEALLOCATE TableCursor;
```