【原创】Oracle管理专题之:Oracle9i 字符集与NLS_LANG搭配测试兼乱码问题分析

【背景介绍】
===================================================================
最近在使用Oracle9i数据库进行数据插入、查询、导入/出,有时会出现乱码的情况,具体的情形有以下两种:

1.首次插入/显示乱码

2.首次插入/显示正常、但把数据用工具导出为本地文件(例如TXT)文件,再在另一个客户端中打开该文件并执行时再次插入的数据显示为乱码。

遂在本地创建两个数据库,一个为AL32UTF8字符集,一个为ZHS16GBK字符集,配合客户端NLS_LANG的不同设置,测试乱码的情况及进行原因分析。    
===================================================================

【测试目的】
===================================================================
测试不同的数据库字符集和客户端NLS_LANG搭配下,中文字符/中文日期的插入、显示
===================================================================

【测试环境】
===================================================================
Windows 2000 Professional (英文版) + Oracle 9.2.0.1.0 + SQL*Plus: Release 9.2.0.1.0

注:此次测试的客户端应用工具为SQL*PLUS,如果是使用TOAD、PL/SQL Develop之类工具,得到的结果会和以下有些不同。推荐使用SQL*PLUS作为一切客户端应用的测试工具
===================================================================

【测试数据库】
===================================================================
本机数据库1: SID: PAULLIN 登陆参数: qprod/qprod@paullin
本机数据库2:SID: PAUL    登陆参数:qlinpen/pengpenglin@paul
===================================================================

【测试字符集】
===================================================================
客户端应用/操作系统字符集:GB2312

客户端NLS_LANG设置:
  AMERICAN_AMERICA.US7ASCII
  AMERICAN_AMERICA.WE8MSWIN1252
  AMERICAN_AMERICA.ZHS16GBK
  AMERICAN_AMERICA.AL32UTF8
  SIMPLIFIED CHINESE_CHINA.ZHS16GBK

数据库端字符集:
  PAULLIN: AL32UF8
  PAUL: ZHS16GBK
===================================================================

【测试脚本】
===================================================================
--登陆数据库    
     sqlplus qprod/qprod@paullin     
     sqlplus qlinpen/pengpenglin@paul

--执行测试脚本
     drop table test;
     drop table testdate;    

     create table test (id number(1), name varchar2(20));
     create table testdate (birthday date);  

     insert into test values(1,'Tom');
     insert into test values(2,'张三');
     insert into test values(3,'易建�');
     commit;
    
     insert into testdate values(TO_Date( '01/08/2008 04:14:00 下午',
           'MM/DD/YYYY HH:MI:SS AM'));
     commit;
    
--查看测试结果    
     select * from test;
     select * from testdate;    
===================================================================

【测试一:数据库端字符集为AL32UTF8的情况】
===================================================================
1.登陆数据库:
  C:\Documents and Settings\qlinpen.E0015609D6309>sqlplus qprod/qprod@paullin

2.查看数据库字符集:
  SQL> select * from nls_database_parameters where parameter = 'NLS_CHARACTERSET';    

3.测试内容及测试结果:
  1).客户端NLS_LANG设置为AMERICAN_AMERICA.US7ASCII:
      中文字符测试:插入/显示中文字符均为乱码
      中文日期测试:ORA-01855: AM/A.M. or PM/P.M. required

  2).客户端NLS_LANG设置为AMERICAN_AMERICA.WE8MSWIN1252:
      中文字符测试:插入/显示中文字符均为正常
      中文日期测试:ORA-01855: AM/A.M. or PM/P.M. required
    
  3).客户端NLS_LANG设置为AMERICAN_AMERICA.ZHS16GBK:
      中文字符测试:插入/显示中文字符均为正常
      中文日期测试:ORA-01855: AM/A.M. or PM/P.M. required
  
  4).客户端NLS_LANG设置为AMERICAN_AMERICA.AL32UTF8:
      中文字符测试:插入/显示中文字符均为正常
      中文日期测试:ORA-01855: AM/A.M. or PM/P.M. required
    
  5).客户端NLS_LANG设置为SIMPLIFIED CHINESE_CHINA.ZHS16GBK:
      中文字符测试:插入/显示中文均为正常
      中文日期测试:插入/显示中文日期均为正常,格式为DD-MM-YY(例如:08-1月 -08)  

4.测试结论:
  从测试结果来看,当数据库端字符集为AL32UTF8时,能够使到中文字符被正确插入/显示的NLS_LANG的字符集为:  WE8MSWIN1252、ZHS16GBK、AL32UTF8。
  
  但是要使到中文格式的时间能够被正确插入,则NLS_LANG的LANGUAGE和TERRITORY设置必须为:SIMPLIFIED_CHINESE_CHINA
===================================================================

【测试二:数据库端字符集为ZHS16GBK的情况】
===================================================================
1.登陆数据库:
  C:\Documents and Settings\qlinpen.E0015609D6309>sqlplus qlinpen/pengpenglin@paul

2.查看数据库字符集:
  SQL> select * from nls_database_parameters where parameter = 'NLS_CHARACTERSET';    

3.测试内容及测试结果:
  1).客户端NLS_LANG设置为AMERICAN_AMERICA.US7ASCII:
      中文字符测试:插入/显示中文字符均为乱码
      中文日期测试:ORA-01855: AM/A.M. or PM/P.M. required

  2).客户端NLS_LANG设置为AMERICAN_AMERICA.WE8MSWIN1252:
      中文字符测试:插入/显示中文字符均为乱码
      中文日期测试:ORA-01855: AM/A.M. or PM/P.M. required
    
  3).客户端NLS_LANG设置为AMERICAN_AMERICA.ZHS16GBK:
      中文字符测试:插入/显示中文字符均为正常
      中文日期测试:ORA-01855: AM/A.M. or PM/P.M. required
  
  4).客户端NLS_LANG设置为AMERICAN_AMERICA.AL32UTF8:
      中文字符测试:插入/显示中文字符均为乱码
      中文日期测试:ORA-01855: AM/A.M. or PM/P.M. required
    
  5).客户端NLS_LANG设置为SIMPLIFIED CHINESE_CHINA.ZHS16GBK:
      中文字符测试:插入/显示中文均为正常
      中文日期测试:插入/显示中文日期均为正常,格式为DD-MM-YY(例如:08-1月 -08)  

4.测试结论:
  从测试结果来看,当数据库端字符集为ZHS16GBK时,能够使到中文字符被正常插入/显示的NLS_LANG的字符集为:ZHS16GBK。
  
  而且要使到中文格式的时间能够被正确插入,则NLS_LANG的LANGUAGE和TERRITORY设置必须为:SIMPLIFIED CHINESE_CHINA
===================================================================

【测试总结】
===================================================================
从上面两个测试的结果就可以明显看出,把数据库端的字符集设置为AL32UTF8比起ZHS16GBK更加有优势。

UTF8支持从客户端应用字符集为WE8MSWIN1252、ZHS16GBK、AL32UTF8的环境下进行中文字符的插入,而ZHS16GBK只支持客户端应用字符集为ZHS16GBK环境下的的中文字符插入。

其次我们来看看日期格式为:01/08/2008 04:14:00 下午的记录为什么只能在NLS_LANG的LANGUAGE和TERRITORY为SIMPLIFIED CHINESE_CHINA的情况下才能正确插入?

我们知道客户端NLS_LANG的值由3部分构成,即<LANUAGE>_<TERRITORY>.<CHARACTERSET>,而掌管日期中月份和日显示的恰恰就是<LANGUAGE>部分,所以很明显<LANGUAGE>为AMERICAN的情况下,是不可能正确插入的(西方用AM、PM来表示上、下午)。

依次类推,如果以后出现货币和数字格式、地区和计算星期及日期的习惯插入、转换失败,那么我们就要检查第二个元素<TERRITORY>。

你可能感兴趣的:(oracle,乱码,lang,字符集,nls)