DECIMAL

DECIMAL
DECIMAL
类型用于表示具有特定最大精度和固定小数位数的数值。这种数据类型在处理金融、会计或其他需要精确数值计算的场景中非常有用,因为它可以避免浮点数运算的舍入误差。

语法

DECIMAL(precision, scale) NUMERIC(precision, scale)

NUMERIC
NUMERIC
DECIMAL
DECIMAL
的别名,用于兼容其他数据库的迁移脚本。不带参数时
NUMERIC
NUMERIC
默认为
DECIMAL(10, 0)
DECIMAL(10, 0)
。别名在解析时立即转换为规范类型,详见类型别名

  • precision
    precision
    :表示数字的总位数,包括小数点两侧的位数。取值范围为 1 到 38。
  • scale
    scale
    :表示小数点后的位数。取值范围为 0 到
    precision
    precision
    ,且不能大于
    precision
    precision
  • 整数部分位数 =
    precision - scale
    precision - scale
    。例如
    DECIMAL(10, 2)
    DECIMAL(10, 2)
    最多存 8 位整数 + 2 位小数;
    DECIMAL(5, 5)
    DECIMAL(5, 5)
    是纯小数,整数部分只能为 0。

字面量

DECIMAL 类型的字面量可以使用

BD
BD
后缀来表示:

SELECT 3.14BD; -- DECIMAL 类型的 3.14 SELECT 1234BD; -- DECIMAL 类型的 1234

不带后缀的小数字面量(如

3.14
3.14
)默认也会被解析为 DECIMAL 类型。

示例

SELECT CAST(1234.56 AS DECIMAL(10, 2)); -- 结果为 1234.56 SELECT CAST(123.456 AS DECIMAL(5, 3)); -- 结果为 null(整数部分需要 3 位,但 DECIMAL(5,3) 只有 2 位整数位) SELECT CAST(1.23 AS DECIMAL(4, 2)); -- 结果为 1.23 SELECT CAST(1234 AS DECIMAL(6, 2)); -- 结果为 1234.00 SELECT CAST(0.1234 AS DECIMAL(5, 4)); -- 结果为 0.1234 SELECT CAST(123.456 AS DECIMAL(10, 2)); -- 结果为 123.46(小数位四舍五入,不截断) SELECT CAST(999.999 AS DECIMAL(5, 2)); -- 结果为 null(整数部分 999 需要 3 位,DECIMAL(5,2) 只有 3 位整数位,但四舍五入后变 1000.00 需要 4 位,溢出)

越界行为

DECIMAL(10, 2)
DECIMAL(10, 2)
的理论范围为
[-99,999,999.99, 99,999,999.99]
[-99,999,999.99, 99,999,999.99]
(8 位整数 + 2 位小数)。

场景示例结果
正常写入
CAST(99999999.99 AS DECIMAL(10,2))
CAST(99999999.99 AS DECIMAL(10,2))
99999999.99
99999999.99
整数位越界
CAST(100000000.00 AS DECIMAL(10,2))
CAST(100000000.00 AS DECIMAL(10,2))
NULL
NULL
小数进位后越界
CAST(99999999.999 AS DECIMAL(10,2))
CAST(99999999.999 AS DECIMAL(10,2))
NULL
NULL
(四舍五入后进位溢出)
负数越界
CAST(-100000000.00 AS DECIMAL(10,2))
CAST(-100000000.00 AS DECIMAL(10,2))
NULL
NULL
小数位超出 scale
CAST(123.456 AS DECIMAL(10,2))
CAST(123.456 AS DECIMAL(10,2))
123.46
123.46
(四舍五入,不溢出)

运算时的自动类型提升

内存中的算术运算会自动扩展结果类型,不会丢失数据:

-- amount 列类型为 DECIMAL(10, 2),值为 99999999.99 SELECT CAST(99999999.99 AS DECIMAL(10,2)) + 0.01; -- 结果:100000000.00(系统自动将结果类型提升为 DECIMAL(13,2),数据未丢失)

但显式 CAST 回原类型会重新触发越界:

SELECT CAST(CAST(99999999.99 AS DECIMAL(10,2)) + 0.01 AS DECIMAL(10,2)); -- 结果:NULL(100000000.00 超出 DECIMAL(10,2) 范围)

大金额场景建议

大面值货币或高并发累加场景,整数位容易不够用:

  • 金额字段建议使用
    DECIMAL(20, 4)
    DECIMAL(20, 4)
    DECIMAL(30, 6)
    DECIMAL(30, 6)
    ,预留足够整数位
  • ETL 写入前校验越界,避免静默丢数:

-- 检测写入越界:原值非 NULL 但转换后为 NULL,说明发生了溢出 SELECT CASE WHEN amount_str IS NOT NULL AND CAST(amount_str AS DECIMAL(10,2)) IS NULL THEN NULL -- 记录到错误表或抛出异常 ELSE CAST(amount_str AS DECIMAL(10,2)) END AS amount FROM source_table;

算术运算结果类型

对两个

DECIMAL
DECIMAL
类型的值进行算术运算时,结果的
precision
precision
scale
scale
按以下规则计算。

设两个操作数类型为

DECIMAL(p1, s1)
DECIMAL(p1, s1)
DECIMAL(p2, s2)
DECIMAL(p2, s2)

加法与减法

result_precision = max(s1, s2) + max(p1 - s1, p2 - s2) + 1 result_scale = max(s1, s2)

示例

DECIMAL(10, 2) + DECIMAL(8, 4)
DECIMAL(10, 2) + DECIMAL(8, 4)
DECIMAL(13, 4)
DECIMAL(13, 4)

  • scale = max(2, 4) = 4
  • precision = 4 + max(10-2, 8-4) + 1 = 4 + 8 + 1 = 13

乘法

result_precision = p1 + p2 + 1 result_scale = s1 + s2

示例

DECIMAL(10, 2) * DECIMAL(8, 3)
DECIMAL(10, 2) * DECIMAL(8, 3)
DECIMAL(19, 5)
DECIMAL(19, 5)

  • precision = 10 + 8 + 1 = 19
  • scale = 2 + 3 = 5

除法

result_precision = p1 - s1 + s2 + max(6, s1 + p2 + 1) result_scale = max(6, s1 + p2 + 1)

示例

DECIMAL(10, 2) / DECIMAL(8, 3)
DECIMAL(10, 2) / DECIMAL(8, 3)
DECIMAL(19, 11)
DECIMAL(19, 11)

  • scale = max(6, 2 + 8 + 1) = 11
  • precision = (10 - 2) + 3 + 11 = 22

取模 (%)

result_precision = min(p1 - s1, p2 - s2) + max(s1, s2) result_scale = max(s1, s2)

示例

DECIMAL(10, 2) % DECIMAL(8, 3)
DECIMAL(10, 2) % DECIMAL(8, 3)
DECIMAL(8, 3)
DECIMAL(8, 3)

  • scale = max(2, 3) = 3
  • precision = min(10-2, 8-3) + 3 = 5 + 3 = 8

聚合函数

函数结果 precision结果 scale
SUMp + 10s
AVGp + 4s + 4

Precision 超过 38 时的调整

DECIMAL 的最大 precision 为 38。当上述公式计算出的 precision 超过 38 时,系统会进行如下调整:

intDigits = precision - scale adjustedScale = max(min(scale, 6), 38 - intDigits) 最终结果 = DECIMAL(38, adjustedScale)

调整逻辑的核心思路:

  • 优先保证整数部分不丢失(整数位 = 38 - adjustedScale)
  • 小数位至少保留
    min(scale, 6)
    min(scale, 6)
    位(即最少 6 位,除非原始 scale 本身小于 6)
  • 如果整数位已经占满 38 位,则 adjustedScale 退化为
    min(scale, 6)
    min(scale, 6)

示例

DECIMAL(38, 7) + DECIMAL(10, 0)
DECIMAL(38, 7) + DECIMAL(10, 0)
的理论结果为
DECIMAL(39, 7)
DECIMAL(39, 7)
,超过 38 后调整为:

  • intDigits = 39 - 7 = 32
  • adjustedScale = max(min(7, 6), 38 - 32) = max(6, 6) = 6
  • 最终结果:
    DECIMAL(38, 6)
    DECIMAL(38, 6)

与整数运算

当 DECIMAL 与整数类型进行运算时,整数会先被转换为对应的 DECIMAL 类型,再按上述规则计算:

整数类型转换后的 DECIMAL
TINYINTDECIMAL(3, 0)
SMALLINTDECIMAL(5, 0)
INTDECIMAL(10, 0)
BIGINTDECIMAL(20, 0)

如果整数是字面量常量,系统会根据实际值推断更精确的类型(例如常量

5
5
会被推断为
DECIMAL(1, 0)
DECIMAL(1, 0)
而非
DECIMAL(10, 0)
DECIMAL(10, 0)
)。

与浮点数运算

当 DECIMAL 与 FLOAT/DOUBLE 进行运算时,结果类型为 DOUBLE。

使用指南

  • scale
    scale
    为0时,表示数值为整数。
  • precision
    precision
    scale
    scale
    的值相同时,表示数值为纯小数(即所有位数都在小数点后)。
  • 在进行数值转换时,如果转换结果超出了
    DECIMAL
    DECIMAL
    类型的范围,可能会发生数据截断或舍入。
  • 在比较
    DECIMAL
    DECIMAL
    类型的数值时,应考虑其精度和尺度,以避免因舍入误差导致的比较错误。
  • 在多步运算中,precision 可能逐步增长直至触发调整。建议在关键计算节点使用
    CAST
    CAST
    显式控制精度,避免意外的精度损失。

注意事项

  • 在使用
    DECIMAL
    DECIMAL
    类型时,应根据实际需求合理选择
    precision
    precision
    scale
    scale
    的值,以确保数值的精确性和计算的准确性。
  • 除法运算的 scale 至少为 6,即使两个操作数的 scale 都为 0,除法结果也会保留 6 位小数。
  • 当 precision 超过 38 触发调整时,小数部分可能被截断,导致精度损失。如果业务对小数精度敏感,应提前规划操作数的 precision 和 scale,避免触发调整。
联系我们
预约咨询
微信咨询
电话咨询