round(x, d)是四舍五入而非截断,依据下一位数字决定进位;truncate(x, d)是硬截断,直接舍去不判断;负数参数下二者机制不同:round向最近整数靠拢,truncate强制高位归零;浮点类型下round结果不稳定,推荐用decimal保障精度。

ROUND(x, d) 是四舍五入,不是“截断”
很多人误以为 ROUND() 会“截掉多余位数”,其实它先看下一位数字再决定进不进位。比如 ROUND(12.345, 2) → 12.35,因为千分位是 5,所以百分位的 4 进成 5;而 ROUND(12.344, 2) → 12.34,因为千分位是 4,直接舍去。
特别注意:ROUND() 对 FLOAT/DOUBLE 类型行为不稳定——底层二进制表示可能导致 ROUND(1.25, 1) 返回 1.2 而非预期的 1.3。稳妥做法是显式转成 DECIMAL:ROUND(CAST(x AS DECIMAL(10,2)), 1)。
TRUNCATE(x, d) 是硬截断,不看下一位
TRUNCATE() 完全不比较下一位数字,只按位数“砍掉”。TRUNCATE(12.345, 2) → 12.34,TRUNCATE(12.345, 1) → 12.3,哪怕后面是 9 也照砍不误。
它支持负数参数,但逻辑是“从左往右归零”:TRUNCATE(123.45, -1) → 120(个位归零),TRUNCATE(123.45, -2) → 100(十位和个位都归零)。这和 ROUND(123.45, -1) → 120 表面一样,但机制完全不同:后者是四舍五入到十位,前者是强制把个位设为 0。
负数参数下 ROUND 和 TRUNCATE 行为差异明显
当 d 为负数时,两者目的相似(处理整数高位),但结果常不同:
-
ROUND(167.8, -2)→200(百位四舍五入:67.8 ≥ 50,进到 200) -
TRUNCATE(167.8, -2)→100(百位以下全归零,不判断 67.8 大不大) -
ROUND(-167.8, -2)→-200(负数也“远离零”进位) -
TRUNCATE(-167.8, -2)→-100(负号保留,只截整数高位)
这种差异在财务汇总、报表取整时容易引发偏差,尤其当原始值带符号且需向左对齐时,必须确认业务要的是“就近归整”还是“强制归零”。
浮点精度问题会让 ROUND 结果不可靠,TRUNCATE 相对稳定
ROUND() 在 FLOAT 列上运行时,可能因存储误差导致意外结果。例如某列定义为 FLOAT,存了看似 3.15 的值,实际是 3.1499999999999999,这时 ROUND(col, 1) 会返回 3.1 而非 3.2。
TRUNCATE() 虽然也受浮点输入影响,但它不依赖下一位判断,只要小数点后位数确定,截出来的字面值更可预期。不过要注意:它不能修复源头精度问题,只是不放大误差。
真正关键的不是选哪个函数,而是列类型是否该用 DECIMAL —— 如果涉及金额、计费、统计,别让 FLOAT 进数据库第一关。











