MySQL 遊標
阿新 • • 發佈:2020-07-01
MySQL 遊標
- SQL語句是“面向集合程式設計”,重點在於“獲得什麼”,而不是“如何獲得”。
- 有時候我們不需要對查詢結構集的每一條都進行相同的操作,而是隻操作其中的某些行,這時候就需要面向過程的程式設計方法,而遊標就是面向過程程式設計方式的體現
- 遊標就相當於“指標”,它一次只指向一行
- 遊標的作用就是用於對查詢資料庫所返回的記錄進行遍歷,以便進行相應的操作
遊標的使用
宣告(給定結果集)、開啟、通過遊標獲取資料、關閉、釋放遊標
宣告,給定結果集,儲存過程結束後遊標就被清理
DECLARE cursor_name CURSOR FOR (SELECT...);
開啟遊標,將結果集送到遊標工作區
OPEN cursor_name;
通過遊標獲取資料
遊標先判斷當前行是否為空,若為空則改變done,若不為空則將資料存放到臨時變數中,讀取後進入下一行為下次讀取做準備。
一定要想明白FETCH的執行方式,不然可能會出現重複FETCH到資料的情況
FETCH cursor_name INTO (變數名s);
關閉遊標
CLOSE cursor_name;
因為每次呼叫FETCH遊標就會嘗試下一行,因此還要宣告一個
NOT FOUND
處理程式來處理遊標讀取不到下一行的情況DECLARE CONTINUE HANDLER FOR not found SET done = true;
或者
DECLARE CONTINUE HANDLER FOR SQLSTATE ‘02000’ SET done = true;
SQLSTATE '02000'
可以看做和not found
一樣,SQLSTATE '02000'
是當沒有更多的行以供迴圈時出現的一個條件。上面兩種都可行,至於done賦值為true還是為1,就要看done是如何定義的,當然定義為INIT的為可以初始化為true
使用舉例1
現有如下資料表
mysql> select * from t; +----+------+-----------------+ | id | nums | content | +----+------+-----------------+ | 1 | 2 | NULL | | 2 | 6 | 二六一十二 | | 3 | 3 | 三三得九 | +----+------+-----------------+ 3 rows in set (0.00 sec)
我們通過遊標讀取每一行並實現將nums匯入到新資料表中
,在實際工作中這種方式可以大大減少我們"分表"時的操作難度。
DELIMITER //
CREATE PROCEDURE transferData()
BEGIN
DECLARE temp_num INT;
DECLARE done BOOLEAN DEFAULT false;
DECLARE cur CURSOR FOR select nums FROM t;
DECLARE continue HANDLER FOR not found SET done = true;
CREATE TABLE IF NOT EXISTS t2 (auto_id int PRIMARY KEY AUTO_INCREMENT, val int not null);
OPEN cur;
REPEAT
IF NOT done THEN
FETCH cur INTO temp_num;
INSERT INTO t2 (val) VALUES (temp_num);
END IF;
UNTIL done=true END REPEAT;
CLOSE cur;
SELECT * from t2;
END//
DELIMITER ;
執行該儲存過程後自動顯示如下結果:
mysql> select * from t2;
-> //
+---------+-----+
| auto_id | val |
+---------+-----+
| 1 | 2 |
| 2 | 6 |
| 3 | 3 |
| 4 | 3 |
+---------+-----+
4 rows in set (0.00 sec)
我們會發現,為什麼這裡多了一行資料?看起來是被重複FETCH並插入了,究其原因,是因為沒有理清楚FETCH的運作方式---沒有搞清楚什麼時候FETCH會改變done
如果我們改成
CREATE PROCEDURE transferData2()
BEGIN
DECLARE temp_num INT;
DECLARE done BOOLEAN DEFAULT false;
DECLARE cur CURSOR FOR select nums FROM t;
DECLARE continue HANDLER FOR not found SET done = true;
CREATE TABLE IF NOT EXISTS t3 (auto_id int PRIMARY KEY AUTO_INCREMENT, val int not null);
OPEN cur;
REPEAT
FETCH cur INTO temp_num;
IF NOT done THEN
INSERT INTO t3 (val) VALUES (temp_num);
END IF;
UNTIL done=true END REPEAT;
CLOSE cur;
SELECT * from t3;
END//
則結果會符合我們的預期
mysql> select * from t3//
+---------+-----+
| auto_id | val |
+---------+-----+
| 1 | 2 |
| 2 | 6 |
| 3 | 3 |
+---------+-----+
3 rows in set (0.00 sec)