特殊字符(德语变音符号)显示为 ASCII

Special characters (german umlauts) are displayed as ASCII

在我们的数据库中,德语变音符号显示为 ASCII。 这里有一些例子

Ü is displayed as "š"
ä is displayed as "„" 
Ä is displayed as "Ž" 
ö is displayed as "”"
Ö is displayed as "™" 

这里是一些 Oracle 环境变量:

SELECT distinct client_charset FROM v$session_connect_info
WHERE sid = sys_context('USERENV','SID');
retuns Unknown

select * from v$NLS_PARAMETERS;
NLS_LANGUAGE    GERMAN  
NLS_CHARACTERSET    WE8MSWIN1252    

我也注意到,没有设置 NLS_LANG。 有人能告诉我如何检查这是环境变量还是字符编码本身的问题吗?或者如何修复它以便正确显示变音符号? 提前致谢!

第一句话已经错了,一定是“我的客户端应用程序将德语变音符号显示为...” Ž 之类的字符也不是 ASCII。 Oracle 环境变量与您的客户端如何显示任何字符无关。

可能有两个原因:

  • š „ Ž ” ™这样的字符实际上存储在你的数据库中,因为它们插入错误,你只是认为它应该是Ü ä Ä ö Ö

  • 您的客户端使用了错误的字符集。

NLS_LANG 用于告诉数据库“我的客户端使用字符集 XYZ”——不多也不少!好吧,一些客户端继承了自己的字符集设置的 NLS_LANG 值,但情况并非总是如此。

实际答案:

您的数据库中有错误的数据!当您插入数据时,您的客户端正在使用 CP437(Oracle 字符集 US8PC437),但您没有告诉数据库。

最有可能的数据是由 sqlplus 插入的,它继承了 cmd.exe 的代码页,在英语 Windows 机器上默认为 437。 NLS_LANG 字符集设置为 WE8MSWIN1252。当客户端和数据库的字符集相同时,数据传输 byte-by-byte 没有任何转换 - 存在不匹配!

解法:

  • 在你 运行 你的 sqlplus 脚本之前相应地设置 NLS_LANG,例如

    SET NLS_LANG=.US8PC437
    sqlplus ...
    

    语言和地区是可选的,因此可以跳过。

  • 您的数据库使用字符集WE8MSWIN1252,那么您的客户也可以使用它。通过这个你可以插入和显示数据库支持的任何字符(不多也不少)

    chcp 1252
    SET NLS_LANG=.WE8MSWIN1252
    sqlplus ...
    

更正错误数据:

为了更正错误的数据试试这个:

UPDATE table_name SET column_name = CONVERT(column_name, 'WE8MSWIN1252', 'US8PC437');

请注意,这应该只是 one-time 更正。不要将此类更新作为应用程序代码的一部分!

更新

要更正 PL/SQL 代码,请尝试这个(未测试):

像这样创建一个 SQL 脚本:

SET HEADING OFF 
SET FEEDBACK OFF 
SET NEWPAGE NONE 
SET VERIFY OFF 
SET TRIMSPOOL ON 
SET DEFINE OFF 
SET ECHO OFF 
SET TERMOUT OFF
SET PAGESIZE 0
SET LINESIZE 32767
SET LONG 2000000000
SET LONGCHUNKSIZE 32767 

spool PACKAGE_NAME.sql;
SELECT DBMS_METADATA.GET_DDL('PACKAGE', 'PACKAGE_NAME', USER) FROM DUAL t;

spool OFF;
EXIT

而 运行 是这样的

c:\> chcp 437
c:\> SET NLS_LANG=.WE8MSWIN1252
c:\> sqlplus -s ... @<above script>

c:\> SET NLS_LANG=.US8PC437
c:\> sqlplus ... @PACKAGE_NAME.sql