我尝试使用下面的 postgres sql 脚本来设置列“ack”的时间戳键值对,但出现以下错误。有谁知道如何纠正它?当值只是一个简单的字符串而不是时间戳时,我不会遇到问题。
--Sql script
UPDATE TABLE_NAME set ack=jsonb_set(ack , '{clientZ}', '{"timestamp": "ABCDE"}')
--Result I am getting
{"clientZ": {"timestamp": "ABCDE"}} -- this works fine
--Sql script
UPDATE TABLE_NAME set ack=jsonb_set(ack , '{clientZ}', '{"timestamp": to_jsonb(to_char(now(), ''YYYY-MM-DD HH:MI:SS.MS TZHTZM''))}')
--Result I am expecting
{"clientZ": {"timestamp": "2024-10-30 11:31:38.765 -0500"}}
--Error I am getting
SQL Error [42601]: ERROR: syntax error at or near "to_jsonb"
谢谢你的提问!我认为您已经非常接近解决方案了。
jsonb_set 的第三个参数必须是有效的 JSON。在你的例子中,它是
'{"timestamp": to_jsonb(to_char(now(), ''YYYY-MM-DD HH:MI:SS.MS TZHTZM''))}'
,它不是有效的 JSON(to_jsonb(... 部分缺少引号)。to_jsonb 函数不是在字符串中求值,而是逐个字母地进行计算。这可以从仅转换中看出字符串转为 JSON:
-- gives an error about bad JSON
select '{"timestamp": to_jsonb(to_char(now(), ''YYYY-MM-DD HH:MI:SS.MS TZHTZM''))}'::jsonb;
如果要替换整个 JSON 对象,则必须从其元素构造它:
select jsonb_build_object('timestamp', to_char(now(), 'YYYY-MM-DD HH:MI:SS.MS TZHTZM'));
jsonb_build_object |
---|
{"时间戳": "2024-10-30 07:01:17.003 +0100"} |
jsonb_build_object 采用一个键和一个值(或多个)。
然后您可以使用结果作为替换值,如下所示:
select jsonb_set('{"clientZ":{"timestamp":"X"}}',
'{clientZ}',
jsonb_build_object('timestamp', to_char(now(), 'YYYY-MM-DD HH:MI:SS.MS TZHTZM')));
jsonb_set |
---|
{"clientZ": {"时间戳": "2024-10-30 07:02:26.420 +0100"}} |
在您的情况下,似乎没有必要替换包含时间戳的整个对象。如果您可以单独设置时间戳字段,请将时间戳移到
path
数组中:
select jsonb_set('{"clientZ":{"timestamp":"X"}}',
'{clientZ,timestamp}',
to_jsonb(to_char(now(), 'YYYY-MM-DD HH:MI:SS.MS TZHTZM')::text));
我们得到 |jsonb_set| |---------| |{"clientZ": {"timestamp": "2024-10-30 06:48:18.018 +0100"}}|
当然还有其他方法,例如通过连接所有部分来构建 JSON 对象的字符串表示形式,但正确引用所有部分会很乏味,所以这似乎是一个更简单的解决方案。