mysql错误1064存储过程将json值提取到表中的特定列中

mysql错误1064存储过程将json值提取到表中的特定列中,mysql,stored-procedures,mysql-error-1064,Mysql,Stored Procedures,Mysql Error 1064,我想将可变长度的json数据提取到现有表中,但出现以下错误: 错误代码:1064。您的SQL语法有错误;检查与您的MySQL服务器版本相对应的手册,以了解使用“begin declare len int”附近的正确语法;声明i int;声明mykey varchar(60);在第2行声明“myvalue” 有人知道如何解决这个错误,或者如何将可变长度的json数据提取到现有表中吗 这是我的代码: drop procedure if exists wk; delimiter // create

我想将可变长度的json数据提取到现有表中,但出现以下错误:

错误代码:1064。您的SQL语法有错误;检查与您的MySQL服务器版本相对应的手册,以了解使用“begin declare len int”附近的正确语法;声明i int;声明mykey varchar(60);在第2行声明“myvalue”

有人知道如何解决这个错误,或者如何将可变长度的json数据提取到现有表中吗

这是我的代码:

drop procedure if exists wk; 
delimiter // create procedure wk(tb varchar(60), myjson json)   
begin
SET @LEN= (select JSON_LENGTH(myjson));
set @i=1;
set @mykey='initial';
set @myvalue='initial';
set @thekeys= (select JSON_keys(myjson));
set @mysql_1=concat("insert into ",tb," (");
set @mysql_2='(';
while @i < @len*2 do
select 3;
set @mykey = (select substring(substring_index(@thekeys,'"',@i+1),length(substring_index(@thekeys,'"',@i))+2));
set @myvalue = (select json_extract(myjson,concat('$.',@mykey)));
set @mysql_1= concat(@mysql, @mykey,","); 
set @mysql_2= concat(@mysql_2, @myvalue,",") ;
set @i =@i+2
end while;

set @mysql = concat(substring(@mysql_1,-1),") values ", substring(@mysql_2,-1)," );");

PREPARE stmt FROM @mysql;
EXECUTE stmt;

end
  //
delimiter ;
call wk('actor','{"actor_id": 1, "first_name": "NICK"}');
drop程序(如果存在);
分隔符// 创建过程wk(tbvarchar(60),myjson)   
开始
设置@LEN=(选择JSON_长度(myjson));
设置@i=1;
设置@mykey='initial';
设置@myvalue='initial';
设置@thekeys=(选择JSON_keys(myjson));
set@mysql_1=concat(“插入到”,tb,”(“”);
设置@mysql_2='(';
而@i<@len*2
选择3个;
设置@mykey=(选择子串(子串_索引(@thekeys,“,@i+1),长度(子串_索引(@thekeys,“,@i))+2));
设置@myvalue=(选择json_extract(myjson,concat('$,@mykey));
设置@mysql_1=concat(@mysql,@mykey,“,”);
设置@mysql_2=concat(@mysql_2,@myvalue,“,”);
设置@i=@i+2
结束时;
设置@mysql=concat(子字符串(@mysql_1,-1),“”)值,子字符串(@mysql_2,-1),“”;“”;
从@mysql准备stmt;
执行stmt;
结束
//
定界符;
调用wk('actor','{“actor_id”:1,“first_name”:“NICK”});

导致错误的直接原因似乎是过程第二行和第三行的一些非打印字符-直接在
分隔符//
之后,以及
创建过程wk(tb varchar(60),myjson)
的右括号之后

清除这些字符后,将出现另一个错误,该错误将告诉您在结束时(在
设置@i=@i+2
之后缺少分号)之前有另一个语法错误

MySQL通常非常擅长让您确切地知道在试图解析语句时遇到问题的地方,问题直接出现在突出显示的文本之前。这里,它说问题从“开始”开始,问题就在它之前

排除错误后,您的过程将运行并输出“3”两次。但是,@mysql将为NULL,并且不会准备和执行任何语句

我不打算调试代码,因为我认为您将问题复杂化了。当MySQL有非常好的工具为您做的时候,您似乎正在尝试编写自己的例程来解析JSON的某些部分。设置@mykey就是一个很好的例子,在这里,你可以直接使用一个索引到@thekeys数组中,而不是使用子字符串来解析键

mysql> SET @thekeys = JSON_KEYS('{"actor_id": 1, "first_name": "NICK"}');

mysql> SET @mykey = JSON_UNQUOTE(JSON_EXTRACT(@thekeys, '$[1]'));

mysql> SELECT @mykey;
+------------+
| @mykey     |
+------------+
| first_name |
+------------+
如果使用内置的JSON函数,可以使代码更简单,那么您需要担心的就是键值对是否与定义的列名和数据类型匹配

e、 g

分隔符//
如果存在wk,则删除程序//
创建过程wk(tbl VARCHAR(64),myjson)
开始
声明i INT默认值为0;
设置@keys='';
设置@VAL='';
而我0,',',''),
CONCAT('`,@mykey'`');
设置@vals=CONCAT(@vals,如果(字符长度(@vals)>0,
海螺('',@myval'');
设置i=i+1;
结束时;
设置@sql=CONCAT('INSERT INTO`,tbl`,`(',@keys')值(',@vals');');
从@sql准备stmt;
执行stmt;
解除分配准备stmt;
结束//
定界符;
调用wk('actor','{“actor_id”:1,“first_name”:“NICK”});

非常感谢。事实上,我没有使用内置JSON函数的原因是我不知道我会事先从JSON中获得哪些字段。文件可以是可变长度的。例如,我可以获得json中的五个字段,并将值插入表中相应的列中。但在阅读json之前,我不知道是哪五个字段。@chunguanghe如果尝试这种方法,你会发现json字符串中的元素数量并不重要,它们引用的字段也不重要,因为WHILE循环只会依次处理它们,直到用完键/值对为止。
DELIMITER //

DROP PROCEDURE IF EXISTS wk //
CREATE PROCEDURE wk(tbl VARCHAR(64), myjson JSON)
BEGIN
  DECLARE i INT DEFAULT 0;
  SET @keys = '';
  SET @vals = '';

  WHILE i < JSON_LENGTH(myjson) DO
    SET @mykey = JSON_UNQUOTE(JSON_EXTRACT(JSON_KEYS(myjson), CONCAT('$[', i, ']')));
    SET @myval = JSON_UNQUOTE(JSON_EXTRACT(myjson, CONCAT('$.', @mykey)));

    SET @keys = CONCAT(@keys, IF(CHAR_LENGTH(@keys) > 0, ',', ''),
      CONCAT('`', @mykey, '`')); 
    SET @vals = CONCAT(@vals, IF(CHAR_LENGTH(@vals) > 0, ',', ''),
      CONCAT('''', @myval, ''''));
    SET i = i + 1;
  END WHILE;

  SET @sql = CONCAT('INSERT INTO `', tbl , '`(', @keys, ') VALUES (', @vals, ');');

  PREPARE stmt FROM @sql;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;    

END //
DELIMITER ;
CALL wk('actor','{"actor_id": 1, "first_name": "NICK"}');