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

mysql error 1064 stored procedure extract json value into specific columns in table

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

Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'begin declare len int; declare i int; declare mykey varchar(60); declare myvalue' at line 2

有谁知道如何解决这个错误或如何将可变长度的 json 数据提取到现有 table 中?

这是我的代码:

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"}');

错误的直接原因似乎是在您的程序的第二行和第三行出现一些非打印字符 - 直接在 delimiter // 之后,也在 create procedure wk(tb varchar(60), myjson json) 的右括号之后。

清除这些字符后,您会收到另一个错误,告诉您在 end while 之前存在另一个语法错误(set @i =@i+2 后缺少分号)。

MySQL 通常非常擅长让您确切地知道在尝试解析您的语句时它从哪里开始 运行 出现问题,问题直接出现在突出显示的文本之前。在这里,它说问题从 'begin' 开始,问题就在它之前。

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

我不会尝试调试代码,因为我认为您使问题过于复杂了。您似乎在尝试编写自己的例程来解析 JSON 的部分内容,而 MySQL 有非常好的工具可以为您完成这项工作。设置 @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函数可以使代码更简单,那么你只需要担心你的键值对是否匹配定义的列名和数据类型。

例如

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"}');