【问题标题】:How to avoid floating-point arithmetic in a MySQL query?如何避免 MySQL 查询中的浮点运算?
【发布时间】:2021-01-31 00:00:16
【问题描述】:

假设我有两列,A 和 B,它们的类型为 DECIMAL(9,2)

现在,假设我运行以下查询:

SELECT SUM(A) / SUM(B)

我的理解是,这种除法不会通过浮点运算来完成,因为两列都是DECIMAL 类型。这是正确的吗?

另外,假设我运行以下查询:

SELECT SUM(A) / SUM(B) * 100

100 将如何影响查询?这会以某种方式导致 MySQL 进行浮点运算吗?如果是这样,我该如何避免?

【问题讨论】:

  • 请提供结果不同的情况。有避免浮动的理由吗? MySQL 非常擅长总是得到“正确”的答案。
  • @RickJames 我正在进行涉及货币金额的计算。在 Java 中,我会使用 BigDecimals,在 PHP、bcmath 或像砖/数学这样的库中。我不确定什么是 MySQL 中的等价物。根据我的阅读和测试,我列出的查询提供了“正确”的答案,但我想与比我更了解 MySQL 的人再次确认。
  • 我一直在思考这个问题,但唉,我没有明确的答案。对于像美元和美分这样简单加法的简单事物,所有的总和都应该是准确的。但是当你需要除法或银行批准的四舍五入时,我会怀疑。
  • 如果你来了,就跨过那座桥。
  • 我的理解是这种除法不会通过浮点运算完成,因为两列都是 DECIMAL 类型。这是正确的吗? (1) dbfiddle.uk/… (2) dev.mysql.com/doc/refman/8.0/en/precision-math-expressions.html (3) 从实践来看:没有显式 CAST 表达式的结果将四舍五入到最精确的操作数小数位数但不少于 6 .

标签: mysql math decimal bigdecimal


【解决方案1】:

100 将如何影响查询?这会以某种方式导致 MySQL 进行浮点运算吗?如果是这样,我该如何避免?

100 是一个精确值的数字文字,这里我们用小数除以小数乘以​​小数(整数)=> 结果仍然是小数(但精度更高)。

Numeric Literals

精确值数字文字具有整数部分或小数部分,或两者兼而有之。他们可能会签名。示例:1、.2、3.4、-5、-6.78、+9.10。

近似值数字文字以科学记数法表示,带有尾数和指数。可以签署其中一个或两个部分。示例:1.2E3、1.2E-3、-1.2E3、-1.2E-3。

两个看起来相似的数字可能会被区别对待。例如,2.34 是一个精确值(定点)数,而 2.34E0 是一个近似值(浮点)数。

例子:

CREATE TABLE t(A DECIMAL(9,2), B DECIMAL(9,2));

CREATE TABLE r1 AS SELECT SUM(A) / SUM(B) AS result FROM t;

SELECT column_name, column_type FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'r1';
+--------------+---------------+
| COLUMN_NAME  |  COLUMN_TYPE  |
+--------------+---------------+
| result       | decimal(37,6) |
+--------------+---------------+

CREATE TABLE r2 AS SELECT SUM(A) / SUM(B) * 100 AS result FROM t;

SELECT column_name, column_type FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'r2';
+--------------+---------------+
| COLUMN_NAME  |  COLUMN_TYPE  |
+--------------+---------------+
| result       | decimal(40,6) |
+--------------+---------------+

现在使用近似值数字文字100E0

CREATE TABLE r3 AS SELECT SUM(A) / SUM(B) * 100E0 AS result FROM t;

SELECT column_name, column_type FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'r3';
+--------------+-------------+
| COLUMN_NAME  | COLUMN_TYPE |
+--------------+-------------+
| result       | double      |
+--------------+-------------+

db<>fiddle demo


值得注意的是,有些操作可能看起来完全相同,但返回的数据类型不同。例如:

CREATE TABLE r4 AS SELECT POWER(A,2) AS result, A*A AS result2 FROM t;

SELECT column_name, column_type FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'r4';
+--------------+---------------+
| COLUMN_NAME  |  COLUMN_TYPE  |
+--------------+---------------+
| result       | double        |
| result2      | decimal(18,4) |
+--------------+---------------+

【讨论】:

    【解决方案2】:

    这是否会导致 MySQL 进行浮点运算?

    我想说你应该参考 SQL 标准,但作为 MySQL,可能不是计算实践中会发生什么的最可靠方法:)。

    我怎样才能避免[意外的浮动强制转换]?

    我要做的就是明确地将值归为适合您的类型:

    SUM(A) / SUM(B) * CAST(100.0 AS DECIMAL(9,2)) 
    

    明确并有助于为未来的你提供文档。

    【讨论】:

      【解决方案3】:

      与其争论计算的细节,不如格式化结果。例如:

      SELECT ROUND(100 * sum(...) / sum(...), 1) ...
      

      这会给你百分比到小数点后一位。

      当您需要“千位分隔符”(不太可能用于百分比)时,请参阅FORMAT() 函数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-04-24
        • 1970-01-01
        • 2019-07-17
        • 2013-01-29
        • 1970-01-01
        • 2012-11-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多