根本原因是客户端nls_lang与oracle 19c数据库nls_characterset不匹配,oci驱动解码时丢弃或替换为问号;需先查数据库字符集,再设系统级nls_lang环境变量,确保oci驱动版本与navicat位数一致,连接属性中“编码”选项无效。

根本原因是客户端 NLS_LANG 环境变量与 Oracle 19c 数据库的 NLS_CHARACTERSET 不匹配,OCI 驱动在解码时直接丢弃或替换为问号,和 Navicat 界面设置无关。
查清数据库实际字符集是第一步
Navicat 里执行以下 SQL,确认服务端用的到底是什么字符集:
SELECT VALUE FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET';
常见返回值有:AL32UTF8(推荐)、ZHS16GBK(旧系统常见)。别猜,必须查。如果返回 AL32UTF8 却设了 ZHS16GBK 的 NLS_LANG,OCI 内部转换就会失败,中文字段值必然变问号。
Windows 必须设系统级 NLS_LANG 环境变量
Navicat 启动时读取的是操作系统环境变量,不是快捷方式里的临时变量,也不是连接属性里那个“编码”下拉框。
- 右键“此电脑” → “属性” → “高级系统设置” → “环境变量”
- 在“系统变量”里新建变量:
NLS_LANG,值按格式填:AMERICAN_AMERICA.AL32UTF8(数据库是 AL32UTF8 时)AMERICAN_AMERICA.ZHS16GBK(数据库是 ZHS16GBK 时) - 注意:不要写成
SIMPLIFIEDCHINESE_CHINA—— 它在部分 Windows 版本 + OCI 组合下反而触发兼容性问题 - 设置完必须重启 Navicat(不是重连,是彻底关闭再打开)
OCI 驱动版本和位数必须严格匹配
Oracle 19c 推荐搭配官方 Oracle Instant Client 19c 或 21c,且必须与 Navicat 位数一致:
- 64 位 Navicat → 必须指向 64 位
oci.dll(路径不能含bin子目录,应为instantclient_19_12\oci.dll) - 混用 32/64 位会导致连接静默失败,或报
ORA-12154,但更隐蔽的情况是——连接成功、查询返回数据,唯独中文字段全为问号 - 旧版 Instant Client(如 11g/12c)对四字节 UTF-8 支持不完整,即使 NLS_LANG 设对了,生僻字或 emoji 仍可能截断
Navicat 连接属性里的“编码”选项完全无效
这个下拉框只影响 SQL 编辑器加载本地 .sql 文件时的文本识别,和 Oracle 字段值的传输、解码毫无关系。
- 你在这里选
UTF-8或GBK,不会改变 OCI 连接参数,也不会设置NLS_LANG - 它唯一能影响的,是编辑器里写的中文注释是否显示正常,或者
SELECT '测试' FROM DUAL这种字面量是否乱码 - 一旦执行结果中的字段值(比如
SELECT name FROM users)是问号,立刻放弃在这个选项上调试
最常被忽略的点:NLS_LANG 值里不能有空格,也不能漏掉中间的点,比如 AMERICAN_AMERICA . AL32UTF8(带空格)或 AMERICAN_AMERICAAL32UTF8(缺点)都会导致 OCI 降级使用系统默认代码页,从而稳定复现问号乱码。











