JSON_VALUE和路径作为MySQL 8.x中的变量不起作用

bq9c1y66  于 2023-06-21  发布在  Mysql
关注(0)|答案(2)|浏览(192)

我使用MySQL8.0并尝试使用JSON_VALUE来处理存储过程中的数组

CREATE PROCEDURE `tJS` ()
BEGIN
   DECLARE _counter INT DEFAULT 0;
   SET @arr = '["123","3","15"]';

   WHILE _counter < JSON_LENGTH(@arr) DO
     --here I want extract element with index _counter from @arr 
     SET @ix = CONCAT('$[', _counter, ']') ;
     SET @v = JSON_VALUE(@arr, @ix);
     -- some stuff with @v must be here
   END WHILE;
END

我在SET @v = JSON_VALUE(@arr,@ix)行得到错误:

  • “您的SQL语法有错误;检查与您的MySQL服务器版本对应的手册,以获得在'@ix)附近使用的正确语法;“*

正如我发现的,在MySQL 8中,JSON_VALUE只在path(第二个参数)是固定字符串而不是变量时才起作用。
所以,这个命令是有效的:

SET @v = JSON_VALUE(@arr, '$[0]')

此命令会抛出相同的语法错误:

SET @v = JSON_VALUE(@arr, CONCAT('$[', _counter, ']'));

在MySQL 8.0中有没有办法将JSON_VALUE中的第二个参数设置为变量,而不是固定的字符串?

l7wslrjt

l7wslrjt1#

https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-value 说:
path是指向文档中位置的JSON路径。必须是字符串文字值这。
所以答案是否定的,你不能用变量代替路径。
在准备SQL查询字符串之前,将路径表达式连接到SQL查询字符串中,然后可以使用PREPARE and EXECUTE运行动态SQL查询。
但我认为你的方法是不可取的,原因有几个:

  • 使用表达式或变量作为JSON路径,当手册说它不支持这个(你应该在发布到Stack Overflow之前检查文档中的JSON_VALUE())。
  • 当您确实希望使用SQL表达式来处理文档中的离散元素时,使用JSON文档,就像它们是关系数据一样(JSON不是关系数据)。
  • 使用MySQL存储过程来完成一项任务,这在任何其他编程语言中都很容易。
6tqwzwtp

6tqwzwtp2#

下面是一个从JSON数组中获取第一项的快速示例:

SET @counter = 0;
SET @json_doc = '["foo", "bar", "baz"]';
SET @json_path = CONCAT('$[', @counter, ']');
SELECT JSON_UNQUOTE(JSON_EXTRACT(@json_doc, @json_path));

下面是一个更长的示例,它创建了一个测试表并从JSON数组中插入了三个值。

CREATE TABLE `test_table` (`item` VARCHAR(3));

DELIMITER $$
CREATE PROCEDURE `test_procedure`()
BEGIN
    DECLARE _counter INT DEFAULT 0;
    SET @json_doc = '["foo", "bar", "baz"]';

    WHILE _counter < JSON_LENGTH(@json_doc) DO
        SET @json_path = CONCAT('$[', _counter, ']');
        SET @json_value = JSON_UNQUOTE(JSON_EXTRACT(@json_doc, @json_path));
        
        SET @sql = 'INSERT INTO `test_table` (`item`) VALUES ("replace_value")';
        SET @sql = REPLACE(@sql, "replace_value", @json_value);

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

        SET _counter = _counter + 1;
    END WHILE;
END $$
DELIMITER ;

CALL `test_procedure`();
DROP PROCEDURE `test_procedure`;

SELECT * FROM `test_table`;
DROP TABLE `test_table`;

相关问题