mysql5.6解析JSON字符串方式(支持复杂的嵌套格式)

2022-11-13 11:11:55 字符串 解析 嵌套

mysql5.6 解析JSON字符串

支持复杂的嵌套格式

废话不多说,先上代码。

CREATE FUNCTioN `json_parse`(`jsondata` longtext,`keyname` text) RETURNS text CHARSET utf8
BEGIN
	DECLARE delim VARCHAR(128);
	DECLARE	result longtext;
	DECLARE startpos INTEGER;
	DECLARE endpos INTEGER;
	DECLARE endpos1 INTEGER;
  DECLARE findpos INTEGER;
	DECLARE leftbrace INTEGER;
	DECLARE tmp longtext;
  DECLARE tmp2 longtext;
	DECLARE Flag INTEGER;
 
	SET delim = CONCAT('"', keyname, '": "');
	SET startpos = locate(delim,jsondata);
 
	IF startpos > 0 THEN
		SET findpos = startpos+length(delim);
		SET leftbrace = 1;
		SET endpos = 0;
		SET Flag =1;
		get_token_loop: repeat 
				IF substr(jsondata,findpos,2)='\\"' THEN
					SET findpos = findpos + 2;
					iterate get_token_loop;
				ELSEIF substr(jsondata,findpos,2)='\\\\' THEN
					SET findpos = findpos + 2;
					iterate get_token_loop;
				ELSEIF substr(jsondata,findpos,1)='"' AND Flag = 1  THEN 
						SET endpos = findpos;
						SET findpos = LENGTH(jsondata)+1;
						leave get_token_loop;
				END IF;
				SET findpos = findpos + 1;
			UNTIL findpos > LENGTH(jsondata) END repeat;
			
			IF endpos > 0 THEN
				SELECT 
					substr(
						jsondata
						,startpos
						+length(delim)#取出value值的起始位置
						,endpos#取出value值的结束位置
						-(
							startpos
							+length(delim)
							)#减去value值的起始位置,得到value值字符长度
					) INTO result
				FROM DUAL;
				SET result= replace(result,'\\"','"');
				SET result= replace(result,'\\\\','\\');
			ELSE 
				SET result=null;
			END IF;
				
	ELSE
			SET delim = CONCAT('"', keyname, '": {');
			SET startpos = locate(delim,jsondata);
			IF startpos > 0 THEN
				SET findpos = startpos+length(delim);
				SET leftbrace = 0;
				SET endpos = 0;
				SET Flag =0;
	
			get_token_loop: repeat 
					IF substr(jsondata,findpos,2)='{"' THEN
						SET leftbrace = leftbrace + 1;
						SET findpos = findpos + 2;
						iterate get_token_loop;
					ELSEIF substr(jsondata,findpos,2)='\\"' THEN
						SET findpos = findpos + 2;
						iterate get_token_loop;
					ELSEIF substr(jsondata,findpos,3)=': "' THEN
							SET Flag = 1;
							SET findpos = findpos + 3;
							iterate get_token_loop;
					ELSEIF substr(jsondata,findpos,1)='"' THEN
						SET Flag = 0;
					ELSEIF substr(jsondata,findpos,1)='}' AND Flag = 0  THEN
						IF leftbrace > 0 THEN
							SET leftbrace = leftbrace - 1;
						ELSE 
							SET endpos = findpos;
							SET findpos = LENGTH(jsondata)+1;
						END IF;
					END IF;
					SET findpos = findpos + 1;
				UNTIL findpos > LENGTH(jsondata) END repeat;
				
				IF endpos > 0 THEN
					SELECT 
						substr(
							jsondata
							,startpos
							+length(delim)#取出value值的起始位置
							,endpos#取出value值的结束位置
							-(
								startpos
								+length(delim)
								)#减去value值的起始位置,得到value值字符长度
						) INTO result
					FROM DUAL;
					SET result=CONCAT("{",result, '}');
				ELSE 
					SET result=null;
				END IF;
			ELSE 
				SET delim = CONCAT('"', keyname, '": [');
				SET startpos = locate(delim,jsondata);
				IF startpos > 0 THEN
					SET findpos = startpos+length(delim);
					SET leftbrace = 0;
					SET endpos = 0;
 
						SET tmp = substring_index(jsondata,delim,-1);
						SET tmp2 = substring_index(tmp,']',1);
						
				   IF locate('[',tmp2) =0 THEN					
							SET endpos = locate(']',tmp);
							SET endpos = endpos+findpos-1;
					 ELSE
							get_token_loop: repeat 
									IF substr(jsondata,findpos,2)='\\"' THEN
										SET findpos = findpos + 2;
										iterate get_token_loop;
									ELSEIF substr(jsondata,findpos,3)=': "' THEN
											SET Flag = 1;
											SET findpos = findpos + 3;
											iterate get_token_loop;
									ELSEIF substr(jsondata,findpos,1)='[' AND Flag = 0 THEN
										SET leftbrace = leftbrace + 1;
										SET findpos = findpos + 1;
										iterate get_token_loop;
									ELSEIF substr(jsondata,findpos,1)='"' THEN
										SET Flag = 0;
									ELSEIF substr(jsondata,findpos,1)=']' AND Flag = 0  THEN
										IF leftbrace > 0 THEN
											SET leftbrace = leftbrace - 1;
										ELSE 
											SET endpos = findpos;
											SET findpos = LENGTH(jsondata)+1;
										END IF;
									END IF;
									SET findpos = findpos + 1;
								UNTIL findpos > LENGTH(jsondata) END repeat;
					END IF;
					IF endpos > 0 THEN
						SELECT 
							substr(
								jsondata
								,startpos
								+length(delim)#取出value值的起始位置
								,endpos#取出value值的结束位置
								-(
									locate(delim,jsondata)
									+length(delim)
									)#减去value值的起始位置,得到value值字符长度
							) INTO result
						FROM DUAL;
						SET result=CONCAT("[",result, ']');
					ELSE 
						SET result=null;
					END IF;
				ELSE 					
					SET delim = CONCAT('"', keyname, '": ');
					SET startpos = locate(delim,jsondata);
					IF startpos > 0 THEN
						SET endpos = locate(',',jsondata,startpos+length(delim));
						SET endpos1 = locate('}',jsondata,startpos+length(delim));
						IF endpos>0 OR endpos1>0 THEN
								IF endpos1>0 AND endpos1 < endpos OR endpos =0 THEN
									SET endpos = endpos1;
								END IF;
								SELECT 
									substr(
										jsondata
										,startpos
										+length(delim)#取出value值的起始位置
										,endpos#取出value值的结束位置
										-(
											locate(delim,jsondata)
											+length(delim)
											)#减去value值的起始位置,得到value值字符长度
									) INTO result
								FROM DUAL;
								
								IF STRCMP(result,'null')=0 THEN
									SET result=null;
								END IF;
						ELSE 					
							SET result=null;
						END IF;
					ELSE 					
						SET result=null;
					END IF;
				END IF;
			END IF;
	END IF;
	if result='' and RIGHT(keyname,2)='Id' then
		SET result=null;
	end if;
	RETURN result;
END

jsondata需要严格的json格式(注意逗号和分号以及双引号之间的空格)

SET jsondata='{"CurrentPage": 1, "data": [{"config": "123"}, {"config": "456"}], "PageSize": 10}' 
SELECT json_parse(jsondata, 'CurrentPage') INTO CurrentPage;
SELECT json_parse(jsondata, 'data') INTO data;

这边如果想获取config的内容,可以这样处理

        SET count = (LENGTH(data)-LENGTH(REPLACE(data,'},','')))/2+1;
        SET i = 0;
        WHILE i < count DO
            SET SetObject = SUBSTRING_INDEX(SUBSTRING_INDEX(data,'},',i+1),'},',-1);
            IF LENGTH(SetObject)>0 THEN
                SELECT json_parse(SetObject, 'config') INTO config;    
            END IF;
            SET i = i + 1;
        END WHILE;

不足之处,jsondata数据多的情况下,会有效率问题。

mysql5.6及以下解析json方法

之前在公司发现在线的查询平台是MySQL5.6,不能用JSON_EXTRACT,也不能用存储过程,所以只能自己编了一个简单的小查询,几条数据还是能查的,如果数据量大的话,估计耗的资源就会比较多。

先说一下问题的背景

是想在'{"platfORM":"Android","source":"tt","details":null}'这一串东西里面找到source这个key对应的value值。

这个方法是先找到source":"这个字符串的起始位置和长度,这样就能够找到value值的起始位置;再找到这个字符串以后第一个"出现的位置,就能得到value值的结束位置。

再利用substr函数,就可以取出对应的位置。

下面是对应的代码 

SELECT 
'{"platform":"Android","source":"tt","details":null}' as 'sample'
,substr(
  '{"platform":"Android","source":"tt","details":null}'
  ,locate('source":"','{"platform":"Android","source":"tt","details":null}')
   +length('source":"')#取出value值的起始位置
  ,locate(
  		'"'
  		,'{"platform":"Android","source":"tt","details":null}'
  		,locate('source":"','{"platform":"Android","source":"tt","details":null}')
  		+length('source":"')
  		)#取出value值的结束位置
	  -(
	  	locate('source":"','{"platform":"Android","source":"tt","details":null}')
	  	+length('source":"')
	  	)#减去value值的起始位置,得到value值字符长度
  ) as result
FROM DUAL 

运行以后,就得到result的结果,就是tt。如果需要其他元素,就替换一下对应的key值和字段,就好了。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。 

相关文章