当 JSON 对象作为字符串文字插入时,MySQL JSON 列丢失小数精度
Posted
技术标签:
【中文标题】当 JSON 对象作为字符串文字插入时,MySQL JSON 列丢失小数精度【英文标题】:MySQL JSON column loses decimal precision when JSON object inserted as a string literal 【发布时间】:2018-05-14 22:28:53 【问题描述】:我正在尝试将 JSON 文档插入 mysql JSON 列,并注意到其中丢失了小数精度。
"value": 212765.700000000010000
减少到
"value": 212765.7
我尝试通过 MySQL Workbench 直接插入,但我注意到不同的行为取决于我的操作方式。例如:
insert into json_test values ('"value": 212765.700000000010000');
产生相同的结果..但是以下工作:
insert into json_test values (json_object('value', 212765.700000000010000));
我可以生成插入语句,使用适用于单个插入的 json_* 函数调用动态构建 JSON 对象。但我正在使用 JDBC 批量更新,这需要 SQL 具有一致数量的参数(我们的 JSON 文档结构不同,因此这不起作用)或在不使用绑定参数的情况下显式设置值,这显然是一个安全风险。
有什么办法吗?
【问题讨论】:
你能用 "value": "212765.70000000100000" 存储你的 json 对象吗?这样做会强制将值存储为字符串,这意味着精度不会改变。 我们已经考虑过这一点,但理想情况下这是我们最后的选择。希望有人找到更好的解决方法。 你知道吗,我认为这是预期的行为,因为 at this link 他们说 MySQL 将数字存储为整数和双精度数,然后尝试将212765.700000000010000
存储在双精度变量中(我在 java ) 然后打印出来,结果和 MySQL 一样,它认为是双重问题,不要问我为什么 json_object 有效
您可能知道,如果您创建一个双列而不指定精度,那么 MySQL 将进行舍入,就像您在 JSON 中使用双变量时发生的情况一样
我认为this is a related reported bug
【参考方案1】:
正如问题的 cmets 中所述,这似乎是 MySQL 解析包含非整数数值的 JSON 文字的方式的问题,而 DOUBLE 不是最佳数据类型。如果您想将 JSON 作为字符串文字提供以加快批量插入过程,那么一种可能的解决方法是将数值作为 JSON 字符串插入,然后在批量插入完成后更新行:
mysql> SELECT VERSION();
+-------------------------+
| VERSION() |
+-------------------------+
| 5.7.20-0ubuntu0.16.04.1 |
+-------------------------+
1 row in set (0.01 sec)
mysql> CREATE TABLE json_test (id INT PRIMARY KEY, jv JSON);
Query OK, 0 rows affected (0.20 sec)
将数值作为字符串插入 ...
mysql> INSERT INTO json_test (id, jv) VALUES (1, '"value": "212765.700000000010000"');
Query OK, 1 row affected (0.11 sec)
mysql> INSERT INTO json_test (id, jv) VALUES (2, '"whatever": "foo"');
Query OK, 1 row affected (0.06 sec)
mysql> INSERT INTO json_test (id, jv) VALUES (3, '"value": "212765.700000000010000", "whatever": "bar"');
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM json_test;
+----+--------------------------------------------------------+
| id | jv |
+----+--------------------------------------------------------+
| 1 | "value": "212765.700000000010000" |
| 2 | "whatever": "foo" |
| 3 | "value": "212765.700000000010000", "whatever": "bar" |
+----+--------------------------------------------------------+
3 rows in set (0.01 sec)
...然后更新行以将值转换为 DECIMAL:
mysql> UPDATE json_test SET jv = JSON_REPLACE(jv, '$.value', CAST(JSON_EXTRACT(jv, '$.value') AS DECIMAL(21,15))) WHERE JSON_TYPE(JSON_EXTRACT(jv, '$.value')) = 'STRING';
Query OK, 2 rows affected (0.04 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> SELECT * FROM json_test;
+----+------------------------------------------------------+
| id | jv |
+----+------------------------------------------------------+
| 1 | "value": 212765.700000000010000 |
| 2 | "whatever": "foo" |
| 3 | "value": 212765.700000000010000, "whatever": "bar" |
+----+------------------------------------------------------+
3 rows in set (0.01 sec)
mysql> SELECT JSON_TYPE(JSON_EXTRACT(jv, '$.value')) AS jt FROM json_test WHERE id=1;
+---------+
| jt |
+---------+
| DECIMAL |
+---------+
1 row in set (0.01 sec)
【讨论】:
以上是关于当 JSON 对象作为字符串文字插入时,MySQL JSON 列丢失小数精度的主要内容,如果未能解决你的问题,请参考以下文章
对 Python 返回 JSON 作为字符串而不是文字感到困惑
php如何将逗号分隔的多个json格式的字符串作为一个值插入到mysql表中? [复制]
将json插入mysql。 json 字符串是从 json.dumps 中获取的
在spring mvc @ResponseBody中返回文字JSON字符串
SyntaxError:JSON.parse:尝试插入 mysql 时 JSON 数据的第 1 行第 1 列出现意外字符