PLSQL打开数据库对象乱码

发布时间 2023-12-29 23:31:32作者: ROGER_FEDERER

1.问题描述

   PLSQL打开远程数据库对象后,发现其中的中文内容为问号乱码.

 

 

 

 

2.处理方式

   这种情况一般是我们初次安装PLSQL后,未在本地配置与数据库一致的NLS_LANG环境变量,导致远端获取的对象字符集在本地解析时无法识别。

2.1 远程数据库配置情况

   使用 NLS_DATABASE_PARAMETERS 字典视图查看有关于数据库本身的NLS(National Language Support)配置,这些配置值是在数据库初始创建时通过CREATE DATABASE的DDL声明确定的,之后不会再改变:

 

ORACLE SQL REFERENCE文档描述:

You can find the database values of the NLS parameters in the data dictionary view NLS_DATABASE_PARAMETERS. These values are associated with a database by the DDL statement CREATE DATABASE and never change afterwards.

 

 

SELECT * FROM NLS_DATABASE_PARAMETERS; 

 

 

 

 

 

可以看到有关NLS_LANG变量的语言(NLS_LANGUAGE),地区(NLS_TERRITORY)及字符集(NLS_CHARACTERSET)。此处查看到字符集为 ZHS16GBK ,仅支持中文跟英文。

2.2 当前会话配置情况

   通过USERENV函数的'LANGUAGE'参数查询当前会话配置情况(查询结果与本地配置的NLS_LANG环境变量有关,其中末尾字符集与配置的NLS_LANG环境变量无关,返回的是数据库本身的字符集):

 

SELECT USERENV('LANGUAGE') FROM DUAL; 

 

 

 

 

 

查看本地的NLS_LANG环境变量配置(环境变量调整完后,命令窗口查看需要电脑重启才会生效,PLSQL查询只需要重启PLSQL即可生效,无需重启电脑):

set nls_lang 

 

 

 


调整NLSLANG变量值为:AMERICANAMERICA.US7ASCII,重启PLSQL查询USERENV('LANGUAGE'):

 

 

 

 

 

 

可以看到,除了最末尾的字符集外,其他两部分内容与session中查询到的userenv('LANGUAGE')一致。而客户端NLS_LANG变量中第一个参数LANGUAGE的作用,即是客户端(PLSQL)操作时返回的提示信息的语言类型,比如某某报错之类的。


关于userenv函数的官方描述:
   (1) 语法:

 

 

   (2)用途:

 

 

  

 

简单来说,userenv函数就是用来查看当前会话的相关配置信息,一般与本地主机环境相关,但尤其注意本地客户端环境的字符集信息,通过userenv函数是无法查询的,其返回一直是数据库服务端的字符集信息。当然也可以使用ORACLE推荐的 SYS_CONTEXT 函数,配合参数查询,与上面的userenv语句查询效果一致,SYS_CONTEXT函数有更多的参数选择,可以满足更灵活的查询要求:

 

 

SELECT SYS_CONTEXT ('USERENV', 'LANGUAGE') FROM DUAL; 

 

可以看到,当前会话的NLS_LANG参数与实际数据库的参数并不一致,但只要两者的字符集是一致的,一般就可以解析,不会出现乱码。

 

2.3 WINDOWS本地NLS_LANG环境变量配置

  

关于NLSLANG的问题,主要参考ORACLE关于NLSLANG的提问回答: https://www.oracle.com/database/technologies/faq-nls-lang.html

 

这里贴几个与惯常理解不同的点:
   (1)NLS_LANG的三个参数分别确定ORACLE客户端口程序所使用的语言,地区,及其进行数据写入与读取使用的字符集;

 

 


 

  

(2)NLS_LANG的字符集参数并不是改变客户端的字符集,而是使ORACLE服务端口知道客户端口所使用的字符集,从而在从服务端口到客户端口时进行适当的转换。通过NLS_LANG变量并不能真正改变NLS_LANG所使用的字符集(好绕……)

 


 

   (3)如果客户端口程序未定义NLS_LANG,则它也不是默认使用数据库服务端的NLS配置,而是使用默认的 AMERICAN_AMERICA.US7ASCII

 

 

 

 

  

综上所述,客户端出现对象打开乱码现象就是两方的字符集不一致,从一方到一方字符集转换时发生数据损失,需要设置客户端口的字符集与服务端口一致即可,当客户端口字符集包含服务端字符集时,展示从数据库查询到的数据不会有乱码,但写入数据库时,数据库存储的也可能由于转码问题导致错误,所以最好还是两者始终保持一致。

参考文档:https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Functions.html#GUID-D079EFD3-C683-441F-977E-2C9503089982


https://www.oracle.com/database/technologies/faq-nls-lang.html