日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

mysql 为游标赋值_mysql 存储过程之游标

發(fā)布時間:2025/3/19 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 为游标赋值_mysql 存储过程之游标 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

游標(biāo)按我的理解就是用在sql編程中對查詢結(jié)果集的解析,類比jdbc中的resultset對象。FETCH 一行游標(biāo)指針就往下面移動一行,直到所有行被遍歷完成。

游標(biāo)的使用分為4步:

1、定義游標(biāo),指定游標(biāo)名和查詢sql語句

2、打開游標(biāo)

3、fetch 獲取數(shù)據(jù),賦值給變量

4、關(guān)閉游標(biāo)

基本使用

1、數(shù)據(jù)準(zhǔn)備

CREATE TABLE `goods` (

`gid` int(11) NOT NULL COMMENT '主鍵',

`name` char(5) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商品',

`num` int(11) NULL DEFAULT NULL COMMENT '庫存',

PRIMARY KEY (`gid`) USING BTREE

) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------

-- Records of goods

-- ----------------------------

INSERT INTO `goods` VALUES (1, 'cat', 34);

INSERT INTO `goods` VALUES (2, 'dog', 0);

INSERT INTO `goods` VALUES (3, 'pig', 12);

2、定義存儲過程,簡單使用下游標(biāo)

CREATE DEFINER="root"@"%" PROCEDURE "p5"()

BEGIN

# 定義接受sql數(shù)據(jù)的變量

DECLARE row_gid int;

DECLARE row_name varchar(20);

DECLARE row_num int;

# 定義游標(biāo)

DECLARE getgoods CURSOR FOR

select gid, name, num from goods;

# 打開游標(biāo)

OPEN getgoods;

# 獲取數(shù)據(jù),使用一次FETCH就是獲取一行

# 注意需要按列順序的順序賦值

FETCH getgoods INTO row_gid, row_name, row_num;

select row_gid, row_name, row_num;

FETCH getgoods INTO row_gid, row_name, row_num;

select row_gid, row_name, row_num;

FETCH getgoods INTO row_gid, row_name, row_num;

select row_gid, row_name, row_num;

FETCH getgoods INTO row_gid, row_name, row_num;

select row_gid, row_name, row_num;

# 關(guān)閉游標(biāo)

CLOSE getgoods;

END

執(zhí)行下 CALL p5(); 可以看到有三個結(jié)果集

image.png

然而我FETCH 了4次,只有3行。那么產(chǎn)生了游標(biāo)越界錯誤。

1329 - No data - zero rows fetched, selected, or processed

使用REPEAT循環(huán)去FETCH 數(shù)據(jù)

使用循環(huán)去遍歷游標(biāo),將查詢sql所有的數(shù)據(jù)取出。使用count(*)總記錄數(shù)去做循環(huán)的判斷條件。若循環(huán)計數(shù)器大于等于總記錄數(shù)則停止循環(huán)。

CREATE DEFINER="root"@"%" PROCEDURE "p6"()

BEGIN

# 定義接受sql數(shù)據(jù)的變量

DECLARE row_gid int;

DECLARE row_name varchar(20);

DECLARE row_num int;

# 總行數(shù)

DECLARE cnt INT DEFAULT 0;

# 循環(huán)變量i

DECLARE i INT DEFAULT 0;

# 定義游標(biāo)

DECLARE getgoods CURSOR FOR select gid, name, num from goods;

# 查詢總行數(shù)并賦值給 cnt

# 注意這句話一定要放到定義游標(biāo)的下面,否則報錯創(chuàng)建存儲過程失敗!

SELECT COUNT(*) INTO cnt FROM goods;

# 打開游標(biāo)

OPEN getgoods;

# 開始循環(huán)

REPEAT

SET i := i+1;

FETCH getgoods INTO row_gid, row_name, row_num;

select row_gid, row_name, row_num;

UNTIL i>=cnt END REPEAT;

# 循環(huán)結(jié)束

# 關(guān)閉游標(biāo)

CLOSE getgoods;

END

使用游標(biāo)監(jiān)聽器 continue handler 和 exit handler 來完善游標(biāo)的遍歷

上面遍歷游標(biāo),防止越界讀取。使用的是count(*) 額外的去發(fā)出一條查詢,有著額外的性能損耗。事實上不需要這樣,mysql游標(biāo)有提供它的方式。

我們可以使用 handler 監(jiān)聽器,在該監(jiān)聽器中定義sql。等到游標(biāo)被遍歷完便會自動執(zhí)行這個sql。那么我們可以使用一個變量,初始化為0,默認(rèn)未遍歷完。在監(jiān)聽器sql中寫入設(shè)置變量值為1。然后在循環(huán)中使用該變量判斷即可

定義監(jiān)聽器

DECLARE CONTINUE HANDLER FOR NOT FOUND set flag :=1;

CREATE DEFINER="root"@"%" PROCEDURE "p7"()

BEGIN

DECLARE row_gid int;

DECLARE row_name varchar(20);

DECLARE row_num int;

# 定義循環(huán)退出標(biāo)志符變量

DECLARE flag INT DEFAULT 0;

DECLARE getgoods CURSOR FOR select gid, name, num from goods;

# 定義監(jiān)聽器

DECLARE CONTINUE HANDLER FOR NOT FOUND set flag :=1;

OPEN getgoods;

REPEAT

FETCH getgoods INTO row_gid, row_name, row_num;

select row_gid, row_name, row_num;

UNTIL flag=1 END REPEAT;

CLOSE getgoods;

END

執(zhí)行下 call p7();發(fā)現(xiàn)只有3行記錄卻放回4個結(jié)果集。而且第3個和第4個結(jié)果集是相同的。這是一個問題。

image.png

第4次執(zhí)行fetch時是沒數(shù)據(jù)的,那么觸發(fā)not found set flag:=1 ,然后continue一下繼續(xù)執(zhí)行后面的sql語句,那么select row_gid, row_name, row_num;又被執(zhí)行一次,最后一行就被執(zhí)行了2次。

若not found set flag:=1 觸發(fā)后,后面的select不再執(zhí)行即可。那么我們可以使用 exit代替continute,exit和continute的區(qū)別是:exit觸發(fā)后后面的語句不再執(zhí)行!

那么使用exit可以完美解決如下:

CREATE DEFINER="root"@"%" PROCEDURE "p7"()

BEGIN

DECLARE row_gid int;

DECLARE row_name varchar(20);

DECLARE row_num int;

# 定義循環(huán)退出標(biāo)志符變量

DECLARE flag INT DEFAULT 0;

DECLARE getgoods CURSOR FOR select gid, name, num from goods;

# 定義EXIT 監(jiān)聽器

DECLARE EXIT HANDLER FOR NOT FOUND set flag :=1;

OPEN getgoods;

REPEAT

FETCH getgoods INTO row_gid, row_name, row_num;

select row_gid, row_name, row_num;

UNTIL flag=1 END REPEAT;

CLOSE getgoods;

END

執(zhí)行如下,3個返回集沒問題

image.png

除了continue 和exit還有一種undo handler 。undo的功能是觸發(fā)后,前面的語句撤銷,目前mysql不支持

除了使用exit解決,continue 基礎(chǔ)上也是可以的。讓如果一定要使用continue 的話就需要修改下邏輯,提前FETCH 下了。為了避免查詢結(jié)果為空而導(dǎo)致返回空結(jié)果集,就需要使用while循環(huán)代替pepeat循環(huán)。因為pepeat循環(huán)類似do while,它總是先執(zhí)行一次循環(huán)體再判斷的。

那么,while加上continue handler 的正確遍歷方式如下:

CREATE DEFINER="root"@"%" PROCEDURE "p7"()

BEGIN

DECLARE row_gid int;

DECLARE row_name varchar(20);

DECLARE row_num int;

# 定義循環(huán)退出標(biāo)志符變量

DECLARE flag INT DEFAULT 0;

DECLARE getgoods CURSOR FOR select gid, name, num from goods;

# 定義監(jiān)聽器

DECLARE CONTINUE HANDLER FOR NOT FOUND set flag :=1;

OPEN getgoods;

# 提前FETCH下

FETCH getgoods INTO row_gid, row_name, row_num;

# 換成while循環(huán),就不會當(dāng)返回集為null時查出數(shù)據(jù)為空的了

# 注意while循環(huán)的循環(huán)條件為true時才進(jìn)入循環(huán)

WHILE flag=0 DO

select row_gid, row_name, row_num;

FETCH getgoods INTO row_gid, row_name, row_num;

END WHILE;

CLOSE getgoods;

END

總結(jié)

以上是生活随笔為你收集整理的mysql 为游标赋值_mysql 存储过程之游标的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。