我在MySQL表中有一列是文本数据类型的。它包含一些json字符串[{"abc":"1","def":2,"xyz":3}]
我需要将这些json值更新为类似的
[
{
"abc": "1",
"changed": [
{
"def": 2,
"xyz": 3
}
]
}
]
我们如何使用MySQL过程实现这一目标?我是存储过程的新手。
任何帮助都会非常有帮助。预先感谢
答案 0 :(得分:0)
我的看法是,您用所需的值更新该列。 因为假设您使用存储过程并检索该列并执行一些字符串操作任务,所以它只会延迟系统的性能。考虑到这一点和简单性,我建议您只引用具有相关ID的那一列,然后更新为所需的值。
答案 1 :(得分:0)
首先可以通过处理给定的JSON结构开始。
假设结构将保持不变,即[ {}, {}, {}, {}, ...]
。让我们从第一个对象获取内容开始
SET @a := '[{"abc":"1","def":2,"xyz":3}]';
SET @b := JSON_REMOVE( @a, '$[0].def', '$[0].xyz' );
SET @c := JSON_REMOVE( @a, '$[0].abc' );
SET @d := JSON_EXTRACT( @c, '$[0]');
SET @e := JSON_INSERT( @b, '$[0].change', JSON_QUERY( @d, '$' ) ); -- for maria db
/** SET @e := JSON_INSERT( @b, '$[0].change', CAST( @d AS JSON ) ); -- for mysql **/
必须有一种更有效的方法来进行上述操作
我已经在mariadb中完成了所有这些操作,因此您将需要取消注释并可能需要对mysql进行一些修正
我们现在需要确定每次修改所使用的部分。
假设包含数据的表就是这样
DROP TABLE IF EXISTS `json_test`;
/**
-- mysql
CREATE TABLE `json_test` (
`id` SMALLINT(4) UNSIGNED NOT NULL AUTO_INCREMENT,
`json` JSON NOT NULL,
PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
*/
-- maria db
CREATE TABLE `json_test` (
`id` SMALLINT(4) UNSIGNED NOT NULL AUTO_INCREMENT,
`json` LONGTEXT NOT NULL,
PRIMARY KEY(`id`),
CHECK( JSON_VALID(`json`) )
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- add some values to test
INSERT INTO `json_test`(`json`) VALUES
( '[{"abc":"1","def":2,"xyz":3}]' ),
( '[{"abc":"1","def":2,"xyz":3},{"abc":"1","def":2,"xyz":3}]' );
所以要操纵内容并可以说通过程序对其进行更新
DELIMITER //
/**
* This proc uses prepared statements to be able to reproduce the aforementioned example
*
* @note: I am not capturing cases of warnings/errors those you will have to add them by yourself.
*
* @param: `INindex` - INT - the position in the json array
* @param: `INkeep` - VARCHAR(32) - the value to keep, format /\.[a-z]/
* @param: `INmove` - VARCHAR(128) - the values to move, format /^(\.[a-z], )*\.[a-z]$/
* @param: x any other parameter that you would like to add
*/
DROP PROCEDURE IF EXISTS `proc_update_json_test` //
CREATE PROCEDURE `proc_update_json_test`( IN `INid` SMALLINT(4), IN `INindex` INT, IN `INkeep` VARCHAR(32), IN `INmove` VARCHAR(128) )
`bgn_lbl`:BEGIN -- or just begin, use labels to escape some conditions
DECLARE `arrayPos` VARCHAR(32) DEFAULT CONCAT( '$[',`INindex`,']');
DECLARE `encodedJSON` LONGTEXT; -- for mariadb
/** DECLARE `encodedJSON` JSON; -- for mysql **/
IF ( SELECT COUNT(*) FROM `json_test` ) = 0 THEN
SELECT 'no such id. Exiting';
LEAVE `bgn_lbl`;
END IF;
SELECT `json` INTO `encodedJSON` FROM `json_test` WHERE `id` = `INid`;
SET `INkeep` = REPLACE( `INkeep`, '.', CONCAT( `arrayPos`, '.' ) );
SET `INmove` = REPLACE( `INmove`, '.', CONCAT( `arrayPos`, '.' ) );
SET `INmove` = REPLACE( `INmove`, ',', "', '" );
PREPARE `stmt` FROM CONCAT( "SET @b := JSON_REMOVE( '",`encodedJSON`,"', '",`INmove`,"' )" );
EXECUTE `stmt`;
DEALLOCATE PREPARE `stmt`;
-- since this is not feasible to add more than a single key unless if we declare it as a
SET @c := JSON_REMOVE( `encodedJSON`, `INkeep` );
SET @d := JSON_EXTRACT( @c, `arrayPos` );
UPDATE `json_test`
SET `json` = JSON_INSERT( @b, CONCAT( `arrayPos`, '.change' ), JSON_QUERY( @d, '$' ) ) -- for maria db
/** `json` = JSON_INSERT( @b, CONCAT( `arrayPos`, '.change' ), CAST( @d AS JSON ) ) -- for mysql **/
WHERE `id` = `INid`;
END //
DELIMITER ;
要运行该过程并检查结果
CALL `proc_update_json_test`( 2, 1, '.abc', '.def, .xyz' );
SELECT * FROM `json_test`;
您需要进行大量尝试才能使此结构以您希望的任何结构运行。只是为了了解如何访问数据