日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

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

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

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

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

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

2、打開(kāi)游標(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 '庫(kù)存',

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、定義存儲(chǔ)過(guò)程,簡(jiǎn)單使用下游標(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;

# 打開(kāi)游標(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(); 可以看到有三個(gè)結(jié)果集

image.png

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

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)計(jì)數(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)的下面,否則報(bào)錯(cuò)創(chuàng)建存儲(chǔ)過(guò)程失敗!

SELECT COUNT(*) INTO cnt FROM goods;

# 打開(kāi)游標(biāo)

OPEN getgoods;

# 開(kāi)始循環(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)聽(tīng)器 continue handler 和 exit handler 來(lái)完善游標(biāo)的遍歷

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

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

定義監(jiān)聽(tīng)器

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)聽(tīng)器

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個(gè)結(jié)果集。而且第3個(gè)和第4個(gè)結(jié)果集是相同的。這是一個(gè)問(wèn)題。

image.png

第4次執(zhí)行fetch時(shí)是沒(méi)數(shù)據(jù)的,那么觸發(fā)not found set flag:=1 ,然后continue一下繼續(xù)執(zhí)行后面的sql語(yǔ)句,那么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ā)后后面的語(yǔ)句不再執(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)聽(tīng)器

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個(gè)返回集沒(méi)問(wèn)題

image.png

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

除了使用exit解決,continue 基礎(chǔ)上也是可以的。讓如果一定要使用continue 的話就需要修改下邏輯,提前FETCH 下了。為了避免查詢結(jié)果為空而導(dǎo)致返回空結(jié)果集,就需要使用while循環(huán)代替pepeat循環(huán)。因?yàn)閜epeat循環(huán)類(lèi)似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)聽(tīng)器

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

OPEN getgoods;

# 提前FETCH下

FETCH getgoods INTO row_gid, row_name, row_num;

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

# 注意while循環(huán)的循環(huán)條件為true時(shí)才進(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 存储过程之游标的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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