我有一张这样的桌子:
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;
如您所见,它不适用于第3项。预期结果当然与第4行相同; []
是对php中的一个空数组进行json编码的结果,如果该项没有任何设置。
可以进行一个适用于所有情况的查询吗?
PS:我需要做的是更新,即UPDATE test SET settings=JSON_SET(...) WHERE id=?;
答案 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}"]
因此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());