MySQL JSON_SET()与空数组一起使用

时间:2019-07-16 14:56:56

标签: mysql mysql-8.0

我有一张这样的桌子:

CREATE TABLE `test` (
  `id` int(11) NOT NULL,
  `settings` json NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

INSERT INTO `test` (`id`, `settings`) VALUES 
    ('1', '{\"foo\": {\"bar\": 1}}'),
    ('2', '{\"foobar\": 2}'),
    ('3', '[]');

我想向行添加新设置,所以我尝试了JSON_SET

SELECT *, JSON_SET(settings, '$.newFoo', 10) FROM test;

enter image description here

如您所见,它不适用于第3项。预期结果当然与第4行相同; []是对php中的一个空数组进行json编码的结果,如果该项没有任何设置。

可以进行一个适用于所有情况的查询吗?


PS:我需要做的是更新,即UPDATE test SET settings=JSON_SET(...) WHERE id=?;

4 个答案:

答案 0 :(得分:0)

您可以使用CASE .. WHEN条件运算符在单个查询中进行处理。另外,由于settings的数据类型为Json,因此您需要先将Cast()的数据类型设置为字符串(Char)以检查[]

SELECT *, 
       CASE WHEN CAST(settings AS CHAR) = '[]'  
            THEN JSON_SET('{}', '$.newFoo', 10)
            ELSE JSON_SET(settings, '$.newFoo', 10) 
       END AS modified_settings 
FROM test;

Update的查询如下:

UPDATE test 
SET settings = CASE WHEN CAST(settings AS CHAR) = '[]'  
                    THEN JSON_SET('{}', '$.newFoo', 10)
                    ELSE JSON_SET(settings, '$.newFoo', 10) 
               END

答案 1 :(得分:0)

JSON_SET的调用未按预期运行的原因是,使用JSON数组所需的语法不同于使用单个JSON所需的语法。考虑以下查询,该查询将JSON添加到空数组:

SELECT JSON_SET('[]', '$[0]', '{"newFoo": 10}') AS output;

此打印:

["{\"newFoo\": 10}"]

Demo

因此JSON_SET函数似乎具有两种行为。在JSON上正常运行时,它可以插入新密钥或更新已经存在的密钥。在对数组进行操作时,它可以插入/更新数组中的元素,这些元素可能是整个JSON对象。

答案 2 :(得分:0)

我通过始终将值存储为对象而不是数组来解决问题,在PHP中,您需要向json_encode函数添加一个标志:

json_encode($value, JSON_FORCE_OBJECT)

或者,作为替代,使该字段可为空并使用COALESCE

SELECT *, JSON_SET(COALESCE(settings, '{}'), '$.newFoo', 10) FROM test;

答案 3 :(得分:0)

这也让我很困惑,但尝试使用JSON_ARRAY()代替双括号符号[[]]。例如:

INSERT INTO `test` (`id`, `settings`) VALUES 
    ('1', '{\"foo\": {\"bar\": 1}}'),
    ('2', '{\"foobar\": 2}'),
    ('3', JSON_ARRAY());