使用mysql存储过程来遍历json数组的值

本文介绍如何在MySQL5.7及以上版本中使用存储过程遍历JSON数组。通过创建存储过程,动态构造SQL,遍历并提取JSON字段中的值,将结果存储在临时表中,最后返回结果集。

mysql存储过程来取出json类型中的值

mysql的版本要是5.7及以上才行,因为在5.7才支持json类型。

  1. *技术不是很好,现在就是写一些存储过程,前段时间需要做一个权限的划分之类的功能。类似A类用户可以查看其下的B类用户工作进展。然后最初想的是直接一对多的映射,将A的用户表中的ID和其对应的B类用户的ID集合一 一对应,这样就能实现简单的一对多。因为mysql有set类型,就想使用set字段来将B类用户的ID存入,然后遍历出来,奈何找了很多教程和文档发现取不出来。后来想到既然是ID组合,能不能用数组来实现,然后json刚好有json数组和json对象类型两种,话不多说来试一下吧。
    DROP TABLE IF EXISTS json;
    CREATE TABLE json (
    ID int(11) NOT NULL,
    IDJSON json NULL COMMENT ‘人员ID,json’,
    PRIMARY KEY (ID) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    可以看到这张表是没有主键的 因为我们这张表就是来存储user表里的ID字段和ID字段组成的json数组的,目标就是遍历出ID字段对应的IDJSON字段中的值

向表里插入几条记录
INSERT INTO json VALUES (17, ‘[25, 31, 33, 37, 69, 71, 73, 75]’);
INSERT INTO json VALUES (21, ‘[25, 31, 33, 37, 39, 67, 69, 71, 73, 75]’);
INSERT INTO json VALUES (175, ‘[25, 31, 33, 37, 39, 67, 69, 71, 75]’);
可以看到IDJSON字段插入时是一个json数组形式字符串,如果不是json类型就会报错。
最终表里的数据是这样的:
在这里插入图片描述
然后我们开始写存储过程来遍历出IDJSON字段中的值

CREATE DEFINER=root@% PROCEDURE proc_json_array(
i_userid int(11)
)
BEGIN
declare i int default 0;
declare v_length int(11);-- 接收数组的长度
declare v_a varchar(100);-- 接收数组的角标的变量
select json_length(IDJSON) into v_length from json where ID=i_userid;
DROP temporary TABLE IF EXISTS tmp_t;
create temporary table if not exists tmp_t(-- 创建临时表保存查询的结果集中的需要的数据
USERID int(11)
);
while i<v_length
do
set v_a=concat("’$[",i,"]’");
set @sql=concat(‘insert into tmp_t(USERID) select IDJSON->’,v_a ,’ from json where ID=’,i_userid);
prepare s from @sql;
execute s;
set i=i+1;
end while;
select USERID from tmp_t;
END

可以看到存储过程需要输入一个int类型参数i_userid 就是表中的ID字段的值。
然后declare声明了一个int型的变量i,它是用来保存循环的次数,然后定义了v_length变量来保存ID字段对应的IDJOSN字段中json数组的长度,接收数组下角标的变量就不说了,然后创建一个只有一个字段USERID的临时表tmp_t.用来将我们遍历出来的值插入进临时表,然后遍历完成后再一次性查出来,这样就只有一个结果集,下面的循环体中从数组的为0 的角标开始取值,因为用到变量所以就想到concat构造动态sql每次取出一个值就执行一次插入临时表的操作,遍历完成然后再查临时表的数据字段即可。 执行存储过程,输入参数17,得到的结果集为,需要注意的是操作j’son类型时的注意点,set v_a=concat("’[&quot;,i,&quot;]′&quot;);此处拼接出来的应为′[&quot;,i,&quot;]&#x27;&quot;);此处拼接出来的应为&#x27;[",i,"]");[i]'这样的形式,可以使用转义字符,@sql的拼接也要注意单引号处的操作。
在这里插入图片描述
这里只是对单层的json数组进行遍历,当然如果是多个字段类型的json如[{“A”:“VAL”,“B”:“VAL”},{“A”:“VAL”,“B”:“VAL”}]时只需在创建临时表时多一个字段,然后在值时参考mysql文档中json字段的用法就能取出。本人在使用时只是用来满足用户一对多的关系,比如A类用户的user表ID主键为1,user表中的B类用户ID为7,8,9,10,11,12需要和ID为1的用户关联表明他们之间的从属关系,那么只需在json表新增条记录ID为1,IDJSON值为[7, 8, 9, 10, 11, 12]即可 然后执行上述存储过程,输入1,得到单列多条的7,8,9,10,11,12结果集,如果需要查看这些用户的信息可以在存储过程的end之前加如下语句
select user表字段1,user表字段2… from user where ID IN(select USERID from tmp_t);
这样在第二个结果集就得到了这些用户的信息。
result1
在这里插入图片描述

result2

在这里插入图片描述

mysql的版本要是5.7及以上才行,因为在5.7才支持json类型。

<think>我们正在讨论MySQL遍历指定数组的问题。注意,MySQL本身没有数组类型,但我们可以通过其他方式模拟数组遍历。常见方法包括:1.使用JSON数组MySQL5.7+支持JSON函数)2.使用临时表或表变量存储数组元素3.使用字符串拆分(如逗号分隔的字符串)根据用户引用的内容[^1]提到使用JSON_TABLE函数遍历JSON数组,这是MySQL8.0引入的功能。因此,如果用户使用的是MySQL8.0及以上版本,推荐使用JSON_TABLE。然而,用户的问题是如何在存储过程遍历一个指定的数组(可能是任意数组)。由于存储过程中并没有原生的数组类型,我们需要将数组以某种形式传入。这里我们考虑两种常见传入方式:a)传入一个JSON数组字符串(如'["a","b","c"]')b)传入一个逗号分隔的字符串(如'a,b,c')然后拆分下面分别提供这两种方式的示例,并给出在存储过程中循环遍历的代码。方法一:使用JSON数组(需要MySQL8.0+)我们可以使用JSON_TABLE函数将JSON数组转换为一个临时表,然后使用游标或WHILE循环(结合计数器)来遍历。在存储过程中,更直接的方式是使用游标。方法二:使用字符串拆分(适用于所有版本,但需要自定义拆分逻辑)注意:由于存储过程中的循环需要,我们可能会使用游标或者使用循环计数器。这里分别给出示例。由于用户之前的问题涉及到存储过程循环指定次数,这里我们可以结合计数器来实现。但首先,我们以JSON数组为例(方法一):假设传入的JSON数组为`['apple','banana','cherry']`,我们想要遍历每个元素。步骤:1.使用JSON_LENGTH获取数组长度2.使用循环计数器从0到长度-1(因为JSON数组索引从0开始)3.使用JSON_EXTRACT提取每个位置的元素我们也可以使用游标,但游标通常用于查询结果集。这里我们使用循环计数器。示例存储过程(方法一:JSON数组遍历使用WHILE循环):```sqlDELIMITER//CREATEPROCEDUREtraverse_json_array(INjson_arrayJSON)BEGINDECLAREarray_lengthINT;DECLAREiINTDEFAULT0;DECLAREelementVARCHAR(255);--获取JSON数组的长度SETarray_length=JSON_LENGTH(json_array);--循环遍历WHILEi< array_lengthDO--提取第i个元素(索引从0开始)SETelement=JSON_UNQUOTE(JSON_EXTRACT(json_array,CONCAT('$[',i,']')));--在这里处理每个元素,例如打印SELECTelement;--计数器递增SETi=i+1;ENDWHILE;END//DELIMITER;```调用示例:```sqlCALLtraverse_json_array('["apple","banana","cherry"]');```方法二:使用逗号分隔的字符串(适用于所有版本)我们可以通过一个循环,每次取一个分隔的子串,直到取完。这里需要使用字符串函数(如SUBSTRING_INDEX)。注意:这种方法需要确保字符串中没有包含分隔符,或者对分隔符进行转义。这里以逗号分隔为例。步骤:1.将字符串按逗号拆分成多个部分,并统计部分的个数(通过计算逗号个数+1)2.使用循环,每次取一个部分,然后更新字符串(去掉已经取出的部分)示例存储过程(方法二:字符串分割遍历):```sqlDELIMITER//CREATEPROCEDUREtraverse_string_array(INstrVARCHAR(255),INdelimiter_charVARCHAR(10))BEGINDECLAREremainderVARCHAR(255)DEFAULTstr;DECLAREelementVARCHAR(255);DECLAREposINT;DECLAREpart_countINTDEFAULT0;DECLAREiINTDEFAULT1;--如果分隔符为空,则设置默认逗号IFdelimiter_char=''ORdelimiter_charISNULLTHENSETdelimiter_char=',';ENDIF;--计算元素个数(通过计算分隔符的个数)SETpart_count=(LENGTH(str)-LENGTH(REPLACE(str,delimiter_char,'')))/LENGTH(delimiter_char)+1;--循环获取每个元素WHILEi<=part_countDO--取第一个元素(从remainder中)SETpos=LOCATE(delimiter_char,remainder);IFpos=0THEN--最后一个元素SETelement=remainder;ELSESETelement=SUBSTRING(remainder,1,pos-1);ENDIF;--更新剩余字符串(去掉已经取出的部分和分隔符)IFpos=0THENSETremainder='';ELSESETremainder=SUBSTRING(remainder,pos+LENGTH(delimiter_char));ENDIF;--处理元素SELECTelement;SETi=i+1;ENDWHILE;END//DELIMITER;```调用示例:```sqlCALLtraverse_string_array('apple,banana,cherry',',');```注意:上述字符串分割的方法在元素包含分隔符时会有问题,需要更复杂的处理(如转义)。因此,如果使用MySQL8.0+,推荐使用JSON数组方式。另外,用户引用的[^1]中提到了JSON_TABLE,这是另一种处理JSON数组的方式,但通常用于SQL查询中直接生成表。在存储过程中,我们可以将JSON_TABLE的结果集用游标遍历。这里给出一个使用游标的例子:使用JSON_TABLE和游标遍历JSON数组(需要MySQL8.0+):```sqlDELIMITER//CREATEPROCEDUREtraverse_json_with_cursor(INjson_arrayJSON)BEGINDECLAREdoneBOOLEANDEFAULTFALSE;DECLAREelement_valVARCHAR(255);--声明游标DECLAREcurCURSORFORSELECTj.valueFROMJSON_TABLE(json_array,'$[*]'COLUMNS(valueVARCHAR(255)PATH'$'))ASj;--声明continuehandlerDECLARECONTINUEHANDLERFORNOTFOUNDSETdone=TRUE;OPENcur;read_loop:LOOPFETCHcurINTOelement_val;IFdoneTHENLEAVEread_loop;ENDIF;--处理元素SELECTelement_val;ENDLOOP;CLOSEcur;END//DELIMITER;```调用示例:```sqlCALLtraverse_json_with_cursor('["apple","banana","cherry"]');```综上所述,我们有多种方法可以在MySQL存储过程遍历数组。根据MySQL版本和数组的传入方式选择合适的方法。最后,根据指令,生成相关问题。</think> 在 MySQL遍历指定数组的实现方法主要有两种,分别适用于不同场景和 MySQL 版本: ### 方法一:使用 JSON 函数(推荐,MySQL 8.0+) 对于 MySQL 8.0+ 版本,推荐使用 JSON 函数处理数组: ```sql DELIMITER // CREATE PROCEDURE traverse_json_array(IN json_array JSON) BEGIN DECLARE array_length INT; DECLARE counter INT DEFAULT 0; -- 获取数组长度 SET array_length = JSON_LENGTH(json_array); -- 遍历数组 WHILE counter < array_length DO -- 提取当前元素(JSON索引从0开始) SET @element = JSON_EXTRACT(json_array, CONCAT('$[', counter, ']')); -- 实际业务逻辑(示例) SELECT @element AS current_value; SET counter = counter + 1; END WHILE; END // DELIMITER ; -- 调用示例(JSON格式数组) CALL traverse_json_array('["apple", "banana", "cherry"]'); ``` #### 关键点解析 1. **JSON 输入参数**:`IN json_array JSON` 接受 JSON 格式的数组 2. **数组长度获取**:`JSON_LENGTH()` 获取数组元素数量 [^1] 3. **元素提取**:`JSON_EXTRACT()` 按索引获取特定元素(索引从 0 开始) 4. **循环控制**:使用 `WHILE` 循环遍历每个元素 [^2] ### 方法二:字符串分割数组(兼容旧版) 对于 MySQL 5.7 或更早版本,可将字符串作为数组处理: ```sql DELIMITER // CREATE PROCEDURE traverse_string_array(IN str_array VARCHAR(255)) BEGIN DECLARE rest_str VARCHAR(255) DEFAULT str_array; DECLARE current_pos INT; DECLARE element VARCHAR(50); WHILE rest_str != '' DO -- 查找分隔符位置 SET current_pos = LOCATE(',', rest_str); IF current_pos = 0 THEN SET element = rest_str; SET rest_str = ''; ELSE SET element = LEFT(rest_str, current_pos - 1); SET rest_str = SUBSTRING(rest_str, current_pos + 1); END IF; -- 实际业务逻辑(示例) SELECT element AS current_value; END WHILE; END // DELIMITER ; -- 调用示例(逗号分隔) CALL traverse_string_array('apple,banana,cherry'); ``` #### 关键点解析 1. **字符串处理**:使用 `LOCATE()`, `LEFT()`, `SUBSTRING()` 分割字符串 2. **循环逻辑**:每次迭代处理一个元素并更新剩余字符串 3. **结束条件**:当 `rest_str` 为空时退出循环 ### 实用建议 1. **数据类型选择** - 新项目首选 JSON 格式(支持复杂数据结构) - 简单数据可用逗号分隔字符串(兼容性好) 2. **性能优化** - 大型数组避免在存储过程中逐元素处理 - 对于数据操作,建议使用基于集合的操作(JOIN、子查询) 3. **边界处理** - 空数组检查:`IF array_length = 0 THEN...` - 无效输入处理:使用 `JSON_VALID()` 验证 JSONMySQL 8.0+ 中,亦可使用 `JSON_TABLE()` 直接转换 JSON 数组为表进行查询: ```sql SELECT j.value FROM JSON_TABLE( '["apple", "banana", "cherry"]', '$[*]' COLUMNS(value VARCHAR(20) PATH '$') ) AS j; ``` [^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值