char()和ascii()是一对互逆函数:ascii()将单个字符转为0–255内的整数,char()将该整数转回字符;二者仅处理单字节值,对中文、全角空格、零宽空格等无效。

CHAR 和 ASCII 函数本身不直接“清洗”数据,但它们是定位和识别脏字符最轻量、最可靠的第一步工具——尤其当你连“哪里脏”都还没看清时。
CHAR() 和 ASCII() 是什么关系?
它们是一对互逆函数:ASCII() 把单个字符转成整数(0–255),CHAR() 把这个整数再转回字符。注意:两者都只处理单字节值,对中文、全角空格、零宽空格等完全无效。
常见错误现象:
- 执行
SELECT CHAR(160)在 MySQL 中返回空字符串或报错,因为 160 是不间断空格(U+00A0)的 Unicode 码点,不是 ASCII 值; - 用
ASCII(' ')(全角空格)得到 227,这只是 UTF-8 编码首字节,不代表该字符语义; - 误以为
CHAR(10)和CHAR(13)能跨数据库通用——PostgreSQL 支持,SQL Server 支持,但某些旧版 SQLite 需启用扩展。
用 ASCII() 快速揪出隐藏控制符
真实脏数据里最常混入的是看不见的控制字符:换行(LF=10)、回车(CR=13)、制表符(TAB=9)、垂直制表(VT=11)、退格(BS=8)。这些不会被 TRIM() 清掉,但 ASCII() 能立刻暴露它们。
使用场景:
- 检查字段末尾是否有隐式换行:
SELECT name, ASCII(RIGHT(name, 1)) FROM users WHERE name LIKE '%张三%'; - 批量扫描某列是否含制表符:
SELECT COUNT(*) FROM logs WHERE ASCII(REPLACE(name, ' ', '')) = 9;(先去空格再取首字符) - 结合
CASE WHEN标记异常字符位置:CASE WHEN ASCII(SUBSTRING(desc, 5, 1)) IN (9,10,13) THEN 'pos5_bad' END
用 CHAR() 构造可比对的“脏样本”
你没法靠肉眼看出哪条记录带 TAB,但可以主动构造一个 TAB 字符,再用 REPLACE() 或 LIKE 去匹配它。
实操建议:
- 在 WHERE 条件中检测 TAB:
WHERE description LIKE '%' || CHAR(9) || '%'(PostgreSQL)或WHERE description LIKE '%' + CHAR(9) + '%'(SQL Server) - 批量清理首尾 TAB:
UPDATE users SET name = TRIM(CHAR(9) FROM TRIM(name));—— 注意:MySQL 8.0+ 才支持TRIM(char FROM col)语法,老版本得嵌套REPLACE() - 别用
CHAR(160)去匹配全角空格,它根本不是 ASCII 字符;改用 Unicode 函数如UNICODE(N' ')(SQL Server)或ORD('\u3000')(PostgreSQL)
容易踩的坑:ASCII() 不是万能探针
它的能力边界非常明确:
- 输入多字符字符串时,只取第一个字符,
ASCII('a b')返回 97,不是空格的 32; - 遇到 NULL 输入直接返回 NULL,不会报错,容易漏判;
- 对 UTF-8 多字节字符(如中文“中”)返回首字节值(228),这个数字毫无业务意义;
- 不同数据库对超出 0–255 范围的输入行为不一致:SQL Server 报错,MySQL 截断取模,PostgreSQL 可能静默失败。
真正复杂的脏字符(零宽空格 U+200B、软连字符 U+00AD、BOM 头等),必须切换到数据库原生的正则或 Unicode 函数,ASCII() 只负责告诉你:“这儿有东西不对劲”,而不是“这是什么”。











