执行 SQL 文件时至少涉及三处字符集Linux Locale由 LANG 或 LC_CTYPE 控制影响 Shell 如何处理文本。SQL*Plus 客户端字符集由 NLS_LANG 控制。SQL 文件实际编码常见是 UTF-8 或 GBK。核心原则很简单SQL 文件编码要和 NLS_LANG 对应的客户端字符集一致再由 Oracle 负责客户端与数据库之间的字符集转换。这里最容易误解的是NLS_LANG 表示客户端字符集不是数据库字符集。02 | UTF-8 文件的推荐配置大多数 Linux 环境和编辑器默认已经使用 UTF-8因此更推荐统一使用 UTF-8。export LANGen_US.UTF-8export NLS_LANGAMERICAN_AMERICA.AL32UTF8如果使用中文 Locale也可以是export LANGzh_CN.UTF-8export NLS_LANGSIMPLIFIED CHINESE_CHINA.AL32UTF8SQL 文件建议保存为UTF-8无 BOM也就是 UTF-8 without BOM如果 SQL 文件本身是 GBK 编码才使用export LANGzh_CN.GBKexport NLS_LANGSIMPLIFIED CHINESE_CHINA.ZHS16GBK03 | 不要盲目照抄数据库字符集很多人看到数据库字符集是 ZHS16GBK就直接设置export NLS_LANGSIMPLIFIED CHINESE_CHINA.ZHS16GBK这只有在客户端 SQL 文件本身也是 GBK 编码时才合适。如果 SQL 文件是 UTF-8而数据库字符集是 ZHS16GBK客户端仍然应该按 UTF-8 设置export NLS_LANGAMERICAN_AMERICA.AL32UTF8此时 Oracle 会完成字符集转换UTF-8客户端↓Oracle Character Conversion↓ZHS16GBK数据库所以排查时不要只盯数据库字符集更要先确认 SQL 文件到底是什么编码。04 | 如何确认文件和数据库字符集查看 SQL 文件编码优先用file test.sqlfile -i test.sql如果输出中看到 charsetutf-8说明是 UTF-8。若显示 UTF-8 Unicode (with BOM)说明文件带 BOM。也可以用 iconv 验证 UTF-8 是否合法iconv -f UTF-8 -t UTF-8 test.sql /dev/nullecho $?返回 0 表示合法 UTF-8如果出现 illegal input sequence说明不是合法 UTF-8。检查是否带 BOMxxd -l 16 test.sql如果文件开头出现ef bb bf说明带 BOM。数据库字符集可以用 SQL 查询SELECT valueFROM nls_database_parametersWHERE parameter ‘NLS_CHARACTERSET’;常见结果可能是 AL32UTF8 或 ZHS16GBK。05 | LC_ALL 不一定要设置通常不需要刻意设置 LC_ALL。Locale 优先级大致是LC_ALL↓LC_*↓LANGSQL*Plus 中文乱码更相关的是LANGLC_CTYPENLS_LANG很多环境只设置下面这一项就够了export LANGen_US.UTF-8LC_ALL 是强制覆盖所有 Locale 设置并不是解决 SQL*Plus 中文乱码的关键。有些系统还可能没有安装对应 Locale导致 cannot change locale。可以先确认系统支持项locale -a06 | 一套稳妥排查顺序遇到乱码时建议依次执行localeecho $LANGecho $NLS_LANGfile -i test.sql再查数据库字符集SELECT valueFROM nls_database_parametersWHERE parameter‘NLS_CHARACTERSET’;笔者更推荐的长期做法是团队统一使用 UTF-8 无 BOM 的 .sql 文件并配置export LANGen_US.UTF-8export NLS_LANGAMERICAN_AMERICA.AL32UTF8
01 | 先看清三个关键角色
执行 SQL 文件时至少涉及三处字符集Linux Locale由 LANG 或 LC_CTYPE 控制影响 Shell 如何处理文本。SQL*Plus 客户端字符集由 NLS_LANG 控制。SQL 文件实际编码常见是 UTF-8 或 GBK。核心原则很简单SQL 文件编码要和 NLS_LANG 对应的客户端字符集一致再由 Oracle 负责客户端与数据库之间的字符集转换。这里最容易误解的是NLS_LANG 表示客户端字符集不是数据库字符集。02 | UTF-8 文件的推荐配置大多数 Linux 环境和编辑器默认已经使用 UTF-8因此更推荐统一使用 UTF-8。export LANGen_US.UTF-8export NLS_LANGAMERICAN_AMERICA.AL32UTF8如果使用中文 Locale也可以是export LANGzh_CN.UTF-8export NLS_LANGSIMPLIFIED CHINESE_CHINA.AL32UTF8SQL 文件建议保存为UTF-8无 BOM也就是 UTF-8 without BOM如果 SQL 文件本身是 GBK 编码才使用export LANGzh_CN.GBKexport NLS_LANGSIMPLIFIED CHINESE_CHINA.ZHS16GBK03 | 不要盲目照抄数据库字符集很多人看到数据库字符集是 ZHS16GBK就直接设置export NLS_LANGSIMPLIFIED CHINESE_CHINA.ZHS16GBK这只有在客户端 SQL 文件本身也是 GBK 编码时才合适。如果 SQL 文件是 UTF-8而数据库字符集是 ZHS16GBK客户端仍然应该按 UTF-8 设置export NLS_LANGAMERICAN_AMERICA.AL32UTF8此时 Oracle 会完成字符集转换UTF-8客户端↓Oracle Character Conversion↓ZHS16GBK数据库所以排查时不要只盯数据库字符集更要先确认 SQL 文件到底是什么编码。04 | 如何确认文件和数据库字符集查看 SQL 文件编码优先用file test.sqlfile -i test.sql如果输出中看到 charsetutf-8说明是 UTF-8。若显示 UTF-8 Unicode (with BOM)说明文件带 BOM。也可以用 iconv 验证 UTF-8 是否合法iconv -f UTF-8 -t UTF-8 test.sql /dev/nullecho $?返回 0 表示合法 UTF-8如果出现 illegal input sequence说明不是合法 UTF-8。检查是否带 BOMxxd -l 16 test.sql如果文件开头出现ef bb bf说明带 BOM。数据库字符集可以用 SQL 查询SELECT valueFROM nls_database_parametersWHERE parameter ‘NLS_CHARACTERSET’;常见结果可能是 AL32UTF8 或 ZHS16GBK。05 | LC_ALL 不一定要设置通常不需要刻意设置 LC_ALL。Locale 优先级大致是LC_ALL↓LC_*↓LANGSQL*Plus 中文乱码更相关的是LANGLC_CTYPENLS_LANG很多环境只设置下面这一项就够了export LANGen_US.UTF-8LC_ALL 是强制覆盖所有 Locale 设置并不是解决 SQL*Plus 中文乱码的关键。有些系统还可能没有安装对应 Locale导致 cannot change locale。可以先确认系统支持项locale -a06 | 一套稳妥排查顺序遇到乱码时建议依次执行localeecho $LANGecho $NLS_LANGfile -i test.sql再查数据库字符集SELECT valueFROM nls_database_parametersWHERE parameter‘NLS_CHARACTERSET’;笔者更推荐的长期做法是团队统一使用 UTF-8 无 BOM 的 .sql 文件并配置export LANGen_US.UTF-8export NLS_LANGAMERICAN_AMERICA.AL32UTF8