SQLite中限制数值列整数10位小数4位无效,ALTER语句是否有误?
嘿,你的ALTER语句语法上完全没问题!之所以插入10.123456没触发你预期的错误,核心原因是大多数数据库对numeric(p,s)类型的默认处理逻辑不是直接报错,而是自动对超出小数位的值做四舍五入或截断,悄悄把值调整到符合列定义的精度后存储。
问题拆解与解决方案
1. 你的ALTER语句本身没有问题
ALTER TABLE scustdisc ADD COLUMN spec_price numeric(10,4) 这个语句是完全合法的:
10代表数值的总位数(小数点前+小数点后)最多10位4代表小数点后最多保留4位
语法和逻辑定义上都没有错误。
2. 为什么插入超精度值不报错?
不同数据库的默认行为略有差异,但核心逻辑一致:
- PostgreSQL:默认会自动将超出小数位的数值四舍五入到指定精度。比如你插入
10.123456,实际存储的是10.1235(四舍五入到4位小数),不会触发错误。 - MySQL:如果没开启严格模式(默认可能没开),同样会自动截断或四舍五入超精度的值,不会报错。只有当
sql_mode包含STRICT_TRANS_TABLES时,才会触发错误。
3. 如何实现“超精度就报错”的预期效果?
根据你使用的数据库类型,有两种常见方案:
方案一:添加检查约束(通用,适合所有支持CHECK的数据库)
给spec_price列添加检查约束,强制要求数值的小数位不超过4位,同时整数部分不超过6位(因为总位数10-小数位4=6):
ALTER TABLE scustdisc ADD CONSTRAINT chk_spec_price_precision CHECK ( -- 限制整数部分最多6位,小数部分最多4位 spec_price BETWEEN -999999.9999 AND 999999.9999 -- 确保小数位不超过4位(乘以10000后是整数) AND (spec_price * 10000) = FLOOR(spec_price * 10000) );
这样再插入10.123456时,就会因为违反检查约束而报错。
方案二:修改数据库模式(针对特定数据库)
MySQL:开启严格模式,修改
sql_mode参数:-- 临时生效,重启数据库后失效 SET sql_mode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION'; -- 永久生效,需要修改my.cnf/my.ini配置文件,添加或修改该行后重启 sql_mode = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION开启后,插入超精度值就会直接触发错误。
PostgreSQL:没有全局的严格模式开关,最可靠的方式就是用上面的检查约束来实现拦截。
内容的提问来源于stack exchange,提问作者ProfileForStack4
相关产品推荐
相关产品推荐

