如何在 MySQL 查询中避免浮点运算?

How to avoid floating-point arithmetic in a MySQL query?

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

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

SELECT SUM(A) / SUM(B)

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

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

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

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

Will this somehow cause MySQL to do floating-point arithmetic?

我想说你应该参考 SQL 标准,但是 MySQL,可能不是计算实际情况的最可靠方法:)。

how can I avoid [unexpected float casts]?

我会做的是明确地将值设为适合您的类型:

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

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

How will the 100 affect the query? Will this somehow cause MySQL to do floating-point arithmetic? If so, how can I avoid it?

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

Numeric Literals

Exact-value numeric literals have an integer part or fractional part, or both. They may be signed. Examples: 1, .2, 3.4, -5, -6.78, +9.10.

Approximate-value numeric literals are represented in scientific notation with a mantissa and exponent. Either or both parts may be signed. Examples: 1.2E3, 1.2E-3, -1.2E3, -1.2E-3.

Two numbers that look similar may be treated differently. For example, 2.34 is an exact-value (fixed-point) number, whereas 2.34E0 is an approximate-value (floating-point) number.

示例:

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


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

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) |
+--------------+---------------+

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

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

这给了你小数点后一位的百分比。

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