ceil、floor与truncate取整逻辑不同:ceil返回≥当前值的最小整数(如ceil(-2.1)=-2),floor返回≤当前值的最大整数(如floor(-2.1)=-3),truncate则直接截断小数部分。

CEIL、FLOOR 和 TRUNCATE 不是同一种取整逻辑,混用会得到完全不同的结果,尤其是负数和小数位控制场景下——别默认它们“差不多”。
CEIL 和 FLOOR 的行为本质是边界判断,不是“向上/向下舍入”
CEIL 返回 ≥ 当前值的最小整数,FLOOR 返回 ≤ 当前值的最大整数。这个定义在正数上看起来像“向上/向下取整”,但负数时立刻翻车:
-
CEIL(-2.1)→-2(因为 -2 > -2.1,且是满足条件的最小整数) -
FLOOR(-2.1)→-3(因为 -3 -
CEIL(0.0)和FLOOR(0.0)都返回0,但输入为NULL时二者都返回NULL,不报错却可能漏数据 - 它们返回类型与输入一致:若输入是
DECIMAL(10,2),结果仍是DECIMAL,小数位显示为.00,后续参与比较或加减可能触发隐式转换
TRUNCATE 是截断,不是取整,且支持小数位控制
TRUNCATE(x, d) 直接砍掉第 d+1 位及之后的所有数字,不四舍五入、不判断正负、不找边界整数:
-
TRUNCATE(3.14159, 2)→3.14 -
TRUNCATE(-3.14159, 2)→-3.14(和FLOOR对负数的行为完全不同) -
TRUNCATE(123.456, 0)→123;TRUNCATE(123.456, -1)→120(注意:d 为负数时截断小数点左侧) - 它不会把
NULL转成0,输入NULL仍返回NULL
GROUP BY 或 ORDER BY 中误用 CEIL/FLOOR 容易触发 ONLY_FULL_GROUP_BY 错误
MySQL 5.7+ 严格模式下,表达式不能直接作为 GROUP BY 列,除非 SELECT 中所有非聚合字段都显式出现在 GROUP BY 里:
- 错误写法:
SELECT CEIL(price), name FROM products GROUP BY CEIL(price)——name既没聚合也没分组 - 正确做法之一:
SELECT CEIL(price), MAX(name) FROM products GROUP BY CEIL(price) - 更稳妥方式:先子查询处理取整,再外层分组,避免表达式干扰语义,例如:
SELECT ceil_price, COUNT(*) FROM (SELECT CEIL(price) AS ceil_price FROM products) t GROUP BY ceil_price - 在
ORDER BY中用于价格区间排序时,FLOOR(price * 10) / 10可能因 DECIMAL 运算引入微小浮点误差,建议统一用ROUND(price, 1)配合FLOOR替代
需要四舍五入或向零截断时,别硬套 CEIL/FLOOR
它们解决不了这些常见需求:
- 四舍五入到百位?用
ROUND(x, -2),不是CEIL(x / 100) * 100 - 向零取整(即去掉小数部分,-2.9 → -2)?
TRUNCATE(x, 0)最直接,FLOOR对负数会变成 -3 - 想确保结果是纯整数类型(如
SIGNED)?得显式转换:CAST(CEIL(x) AS SIGNED)或CONVERT(FLOOR(x), SIGNED) - 性能差异几乎可忽略,但语义清晰更重要:CEIL/FLOOR 适合做分页偏移计算、价格档位划分等有明确上下界意图的场景;TRUNCATE 更适合格式化展示、精度对齐等操作
最容易被忽略的是:CEIL/FLOOR 对负数的处理不是“习惯性理解”的向下/向上,而是严格的数学不等式约束;而 TRUNCATE 的第二参数为负数时,行为容易被低估——它真会把 1234 截成 1200,不是报错也不是忽略。











