提问人:Accountant م 提问时间:3/16/2017 更新时间:3/16/2017 访问量:266
如何在 mysql 中存储十进制计算结果并将其检索回内存中
How to store a decimal calcaulation result in mysql and retrive it back as they were in memory
问:
MySQL文档说:
DECIMAL 和 NUMERIC 类型存储精确的数值数据值。当需要保持精确精度时,例如货币数据,可以使用这些类型。
我在那列上做了这个测试。decimal_column DECIMAL(31,30)
insert into tests (decimal_column) values(1/3);
然后检查存储的内容会得到这个
select * from tests ;
> result : 0.333333333000000000000000000000
然后用这个查询反转数学运算,得到这个
select decimal_column*3 from test;
> result: 0.999999999000000000000000000000
我期望得到整数“1”,因为我们在计算器和 excel 表格中这样做!喜欢这个
#calculator or excel sheet
>input: 1 / 3
>result: 0.3333333333333333333333333333333333
>input: * 3
>result: 1
1- 为什么 MySQL 没有存储 (1 / 3) 的确切二进制表示,所以我可以在计算中再次使用该结果,因为它们像计算器或 Excel 工作表一样在内存中。
阿拉伯数字-如何在计算期间将结果存储在 mysql 中,因为它们在内存中,因此我可以检索确切的值并执行类似将 1 结果为整数之类的操作,就像我们在计算器或 excel 工作表中所做的那样。(1/3)
3 * $storedValue
答:
这取决于您需要信息的内容。
如果存储用于计算和存储,请计算结果(0.33 而不是 1/3)并将其存储为十进制 (1,5)。但是,如果你想显示它,你不能轻易地向后计算它。
如果它被存储为以后显示,但永远不会再次修改(或至少不快速),您可以将其存储为 varchar,但这会破坏排序。
或者您可以存储不同的元素(正数、负数、总数......whatever)作为十进制(5,0)并在使用它时显示/计算它。
当然,如果您想在选择时从计算时间中获得优势,您可以结合上述内容。
MySQL 使用 64 位 IEEE 754 浮点数进行内部分数运算。
它们通常是近似值。期望IEEE浮点数或十进制算术在执行时实现完全相等是完全不合理的
3*(1/3) == 1
这不是计算机算术的工作方式。
也没有办法存储值 1/3 的精确表示,除非您碰巧使用以(分子,分母)对的形式存储有理数(小数)的奇特计算系统。MySQL不是这样的系统。
大多数计算器将其结果隐式舍入到它们可以显示的位数。Excel 也包含一个格式模块。您可以通过按 -1 来选择单元格的格式。格式化模块对这些浮点数进行舍入。您可以使用 ROUND() 函数在 MySQL 中实现相同的效果。该函数不会更改存储的值,但它确实以隐藏 IEEE 754 浮点运算中固有的微小错误的方式呈现它。
SELECT ROUND(decimal_column, 2) AS decimal_column
(会计人员不是必须在学校里学习这些东西吗?
评论
1/3
*3
1.0000000000000000000000000000000000000000001
问题不在于存储。在您的示例中,该值在存储到表中之前已损坏。
不幸的是,如果你写 1/3,它将使用默认表示进行计算(并插入):
SELECT 1/3
0.333333333
如您所见,其精度不足。
另一个问题是,当您向服务器发送常量(1 或 3)时,您需要使用库或连接器来执行此操作,这可以自由使用该值。例如,它可能认为“1”和“3”是整数,它们的结果将被视为整数。因此,您得到“1/3 = 0”,但“1./3 = 0.333333”,因为“1.”中的点使连接器意识到它需要使用其默认浮点。而且你只得到六个 3,因为连接器的“默认浮点数”有 6 位数字。然后将其存储到数据库中,但为时已晚。您正在以高精度存储已被截断为低精度的值。
您可以尝试从一开始就强制转换常量。使用“1”而不是“1”,而是将 1 转换为足够大的小数点。我在这里使用你的 31,30,但请检查您是否不需要存储更大的数字。可能,“31,20”会更好。
mysql> SELECT 1/3 UNION SELECT CAST(1 AS DECIMAL(31,30))/CAST(3 AS DECIMAL(31,30));
+----------------------------------+
| 1/3 |
+----------------------------------+
| 0.333333333000000000000000000000 |
| 0.333333333333333333333333333333 |
+----------------------------------+
2 rows in set (0.00 sec)
这很尴尬,但结果应该更好。另外,我认为只需要在表达式中强制转换一个值;然后,MySQL将根据需要提升所有涉及的数量。因此,将 CAST(0 AS DECIMAL(x,y)) 添加到总和中,将 CAST(1 AS DECIMAL(x,y)) 添加到乘法中可能就足够了。
mysql> SELECT 3*CAST(1 AS DECIMAL(31,30))/CAST(3 AS DECIMAL(31,30));
+-------------------------------------------------------+
| 3*CAST(1 AS DECIMAL(31,30))/CAST(3 AS DECIMAL(31,30)) |
+-------------------------------------------------------+
| 1.000000000000000000000000000000 |
+-------------------------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT CAST(1 AS DECIMAL(31,30))*1/3;
+----------------------------------+
| CAST(1 AS DECIMAL(31,30))*1/3 |
+----------------------------------+
| 0.333333333333333333333333333333 |
+----------------------------------+
1 row in set (0.00 sec)
请注意,这不起作用,因为乘法具有更高的优先级:
mysql> SELECT CAST(0 AS DECIMAL(31,30))+1/3;
+----------------------------------+
| CAST(0 AS DECIMAL(31,30))+1/3 |
+----------------------------------+
| 0.333333333000000000000000000000 |
+----------------------------------+
1 row in set (0.00 sec)
评论
1/3
result * 3
评论