MySQL 的 FORMAT() 第三个参数就是 locale。它不改变原始数值,而是改变返回字符串中的小数点、千分位符号和分组方式:
-- 中文说明:同一个数使用不同地区规则生成展示文本
SELECT FORMAT(12332.2, 2) AS us_default,
FORMAT(12332.2, 2, 'de_DE') AS german_style;
前者按默认的 en_US 规则得到 12,332.20,后者按 de_DE 规则得到 12.332,20。也就是说,千分位从逗号变成了点,小数点从点变成了逗号。
官方地址:https://dev.mysql.com/doc/refman/8.4/en/string-functions.html
FORMAT 的三个参数分别做什么
函数签名是 FORMAT(X, D[, locale])。X 是待格式化的数字,D 是保留的小数位数,locale 是可选的地区规则。函数返回的是字符串,而不是继续参与数值运算的 DECIMAL。
| 参数 | 作用 | 示例 |
|---|---|---|
X | 输入数值 | 12332.2 |
D | 保留的小数位数,并按该位数四舍五入 | 2 |
locale | 决定小数点、千分位和分组规则 | 'de_DE' |
因此,想改变千分位时,不是修改服务器的字符集,也不是替换结果字符串,而是传入第三个参数。
用 locale 切换千分位与小数点
最小对比可以直接写成两列。省略第三个参数时,MySQL 使用默认 locale en_US;传入 de_DE 后,显示规则发生变化。
-- 中文说明:对比默认规则和德语地区规则的分隔符
SELECT FORMAT(12332.123456, 4) AS default_locale,
FORMAT(12332.123456, 4, 'de_DE') AS de_locale;
-- 预期的静态结果:
-- default_locale = 12,332.1235
-- de_locale = 12.332,1235
可以把变化拆成三部分理解:
- 小数点:
en_US使用句点,de_DE使用逗号。 - 千分位:
en_US使用逗号,de_DE使用句点。 - 分组:locale 还决定整数部分如何分组,不应只把它理解成“替换一个字符”。
支持范围、默认值与 NULL 行为
locale 可以使用的值与 lc_time_names 系统变量允许的 locale 相同。省略 locale,或者显式传入 NULL,都会回到默认的 en_US 规则;这两个写法不是切换到某个“当前用户地区”。
-- 中文说明:NULL 的 X 或 D 会让 FORMAT 返回 NULL
SELECT FORMAT(NULL, 2, 'de_DE') AS null_number,
FORMAT(12332.2, NULL, 'de_DE') AS null_digits,
FORMAT(12332.2, 2, NULL) AS null_locale;
-- null_number 和 null_digits 为 NULL;null_locale 使用默认 en_US 规则
如果 D 为 0,结果不包含小数点和小数部分;如果 D 为正数,结果会补足对应的小数位。
-- 中文说明:D 控制小数位,0 表示只显示整数部分
SELECT FORMAT(12332.2, 0) AS no_fraction,
FORMAT(12332.2, 2, 'de_DE') AS two_fraction_digits;
实际项目中,locale 最好来自受控的地区代码列或应用配置。不要把用户任意输入直接拼进 SQL;值应通过参数绑定或白名单映射传递。
把展示格式和数值运算分开
FORMAT() 适合报表、导出和页面展示,不适合把结果当作排序键。因为返回值是带地区分隔符的字符串,字符串排序可能与数值大小排序不一致。
-- 中文说明:展示列格式化,排序仍使用原始数值列
SELECT amount,
region_locale,
FORMAT(amount, 2, region_locale) AS amount_text
FROM invoice_summary
ORDER BY amount DESC;
这里的职责分离是:amount 保留数值语义,FORMAT(amount, 2, region_locale) 只生成当前地区可读的文本,ORDER BY amount 保证排序仍按真实金额。聚合、范围过滤和索引条件也应继续使用原始数值列。
结论与排查清单
- 要改变千分位和小数点,给
FORMAT()传第三个参数locale。 - 省略 locale 或传入 NULL 时,默认按
en_US格式化。 D同时决定四舍五入和小数位数量,0表示不显示小数部分。- FORMAT 返回字符串;排序、聚合、过滤和索引条件继续使用原始数值。
常见问题
为什么 FORMAT 后的小数点变成了逗号?
通常是传入了使用逗号作为小数点的 locale,例如 de_DE。先检查第三个参数,而不是修改字符集。
能不能只改千分位,不改小数点?
FORMAT() 的 locale 同时决定小数点、千分位和分组方式。如果必须使用非标准组合,应在应用展示层处理,并保留数据库中的原始数值。
FORMAT 的结果为什么不能直接拿来做金额排序?
因为它是字符串。应按原始金额列排序,格式化后的别名只用于输出。