SQL*Plus 执行中文 SQL 文件,如何避开乱码坑

在 Linux 上用 sqlplus @xxx.sql 执行脚本时,只要 SQL 文件里有中文字符串或中文注释,就可能遇到乱码。这个问题通常不是数据库本身坏了,而是 SQL 文件编码、Linux Locale、SQL*Plus 客户端字符集没有对齐。

01 | 先看清三个关键角色

执行 SQL 文件时,至少涉及三处字符集:

  • Linux Locale:由 LANGLC_CTYPE 控制,影响 Shell 如何处理文本。
  • SQL*Plus 客户端字符集:由 NLS_LANG 控制。
  • SQL 文件实际编码:常见是 UTF-8 或 GBK。

核心原则很简单:

SQL 文件编码要和 NLS_LANG 对应的客户端字符集一致,再由 Oracle 负责客户端与数据库之间的字符集转换。

这里最容易误解的是:NLS_LANG 表示客户端字符集,不是数据库字符集。

02 | UTF-8 文件的推荐配置

大多数 Linux 环境和编辑器默认已经使用 UTF-8,因此更推荐统一使用 UTF-8。

bash 复制代码
export LANG=en_US.UTF-8
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8

如果使用中文 Locale,也可以是:

bash 复制代码
export LANG=zh_CN.UTF-8
export NLS_LANG=SIMPLIFIED CHINESE_CHINA.AL32UTF8

SQL 文件建议保存为:

  • UTF-8
  • 无 BOM,也就是 UTF-8 without BOM

如果 SQL 文件本身是 GBK 编码,才使用:

bash 复制代码
export LANG=zh_CN.GBK
export NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK

03 | 不要盲目照抄数据库字符集

很多人看到数据库字符集是 ZHS16GBK,就直接设置:

bash 复制代码
export NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK

这只有在客户端 SQL 文件本身也是 GBK 编码时才合适。

如果 SQL 文件是 UTF-8,而数据库字符集是 ZHS16GBK,客户端仍然应该按 UTF-8 设置:

bash 复制代码
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8

此时 Oracle 会完成字符集转换:

text 复制代码
UTF-8(客户端)
↓
Oracle Character Conversion
↓
ZHS16GBK(数据库)

所以排查时不要只盯数据库字符集,更要先确认 SQL 文件到底是什么编码。

04 | 如何确认文件和数据库字符集

查看 SQL 文件编码,优先用:

bash 复制代码
file test.sql
file -i test.sql

如果输出中看到 charset=utf-8,说明是 UTF-8。若显示 UTF-8 Unicode (with BOM),说明文件带 BOM。

也可以用 iconv 验证 UTF-8 是否合法:

bash 复制代码
iconv -f UTF-8 -t UTF-8 test.sql >/dev/null
echo $?

返回 0 表示合法 UTF-8;如果出现 illegal input sequence,说明不是合法 UTF-8。

检查是否带 BOM:

bash 复制代码
xxd -l 16 test.sql

如果文件开头出现:

text 复制代码
ef bb bf

说明带 BOM。

数据库字符集可以用 SQL 查询:

sql 复制代码
SELECT value
FROM nls_database_parameters
WHERE parameter = 'NLS_CHARACTERSET';

常见结果可能是 AL32UTF8ZHS16GBK

05 | LC_ALL 不一定要设置

通常不需要刻意设置 LC_ALL。Locale 优先级大致是:

text 复制代码
LC_ALL
↓
LC_*
↓
LANG

SQL*Plus 中文乱码更相关的是:

  • LANG
  • LC_CTYPE
  • NLS_LANG

很多环境只设置下面这一项就够了:

bash 复制代码
export LANG=en_US.UTF-8

LC_ALL 是强制覆盖所有 Locale 设置,并不是解决 SQL*Plus 中文乱码的关键。有些系统还可能没有安装对应 Locale,导致 cannot change locale。可以先确认系统支持项:

bash 复制代码
locale -a

06 | 一套稳妥排查顺序

遇到乱码时,建议依次执行:

bash 复制代码
locale
echo $LANG
echo $NLS_LANG
file -i test.sql

再查数据库字符集:

sql 复制代码
SELECT value
FROM nls_database_parameters
WHERE parameter='NLS_CHARACTERSET';

笔者更推荐的长期做法是:团队统一使用 UTF-8 无 BOM 的 .sql 文件,并配置:

bash 复制代码
export LANG=en_US.UTF-8
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8

这样可以减少 UTF-8、GBK 混用带来的跨平台问题。

一句话总结:保持 SQL 文件编码、Linux Locale 和 NLS_LANG 一致,让 Oracle 负责客户端与数据库之间的字符集转换,是避免 SQL*Plus 中文乱码的稳妥方案。

关注我,和AI一起成长~

相关推荐
Irene199110 个月前
前端开发易错易忽略的 HTML 的 lang 属性
html·lang