You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

psycopg2保存数据报错:NUMERIC(4,3)字段精度不符合要求

解决Postgres NUMERIC(4,3)与SQLAlchemy Float(3)的数值保存异常问题

问题场景

Postgres表中字段定义为NUMERIC(4,3),SQLAlchemy模型里用Column(Float(3))做映射。用Python的round()处理数值(比如0.034)后保存,会抛出错误:

"A field with precision 4, scale 3 must round to an absolute value less than 10^1"
但直接用SQL的ROUND()函数插入同数值却完全正常。

原因解析

  1. 类型不匹配:SQLAlchemy的Float(3)映射的是Postgres的FLOAT类型,而非表定义的NUMERIC。当Python浮点数(哪怕是round后的结果,比如0.034实际可能是二进制浮点数的近似值0.034000000000000002)传到psycopg2时,会触发FLOAT到NUMERIC的隐式转换,Postgres在转换时会因浮点数精度误差误判数值超出范围。
  2. 字段规则明确:NUMERIC(4,3)要求总位数4位、小数位3位,整数部分最多1位,合法取值范围是-9.999到9.999。SQL的ROUND()返回的是NUMERIC类型,和字段类型完全匹配,不会有转换偏差。

解决方案

1. 修正模型字段类型(核心)

把SQLAlchemy中的Float(3)替换为Numeric(4, 3),让ORM字段和数据库字段类型完全对应:

from sqlalchemy import Numeric

@dataclass
class TableName(TableBase):
    __tablename__ = 't_cal_table_name'
    __table_args__ = ([constraints_and_stuff])

    # ...其他字段...
    first_second_ratio = Column(Numeric(4, 3), nullable=False)
    second_double_fault_ratio = Column(Numeric(4, 3), nullable=False)
    # ...其他字段...

2. 用Decimal处理数值(避免浮点数误差)

如果需要在Python中计算并格式化数值,改用decimal.Decimal代替float,彻底消除二进制浮点数的精度问题:

from decimal import Decimal, ROUND_HALF_UP

# 用Decimal进行除法计算
first_second_ratio = Decimal(first_serve_sum) / Decimal(second_serve_sum)
# 四舍五入到3位小数
first_second_ratio = first_second_ratio.quantize(Decimal('0.000'), rounding=ROUND_HALF_UP)

3. 前置数值范围校验

保存前手动检查数值是否在合法范围内,提前拦截异常:

def validate_ratio(value):
    if not (-9.999 <= value <= 9.999):
        raise ValueError(f"数值{value}超出NUMERIC(4,3)范围")
    return value

first_second_ratio = validate_ratio(round(first_serve_sum / second_serve_sum, 3))

内容的提问来源于stack exchange,提问作者Tamás Király

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 19:02:11