今天被字符集搞晕了

今天看字符集的相关视频,里面讲到
NLS_LANG要和操作系统使用的字符集设置一致

[oracle@gc1:/home/oracle]$ locale
        LANG=en_US.UTF-8
        LC_CTYPE="en_US.UTF-8"
        LC_NUMERIC="en_US.UTF-8"
        LC_TIME="en_US.UTF-8"
        LC_COLLATE="en_US.UTF-8"
        LC_MONETARY="en_US.UTF-8"
        LC_MESSAGES="en_US.UTF-8"
        LC_PAPER="en_US.UTF-8"
        LC_NAME="en_US.UTF-8"
        LC_ADDRESS="en_US.UTF-8"
        LC_TELEPHONE="en_US.UTF-8"
        LC_MEASUREMENT="en_US.UTF-8"
        LC_IDENTIFICATION="en_US.UTF-8"
        LC_ALL=


sys@PROD>select * from nls_database_parameters;
PARAMETER                           VALUE
-------------------------- --------------------------------------------------------------------------------
NLS_LANGUAGE                       AMERICAN
NLS_TERRITORY                       AMERICA
NLS_CURRENCY                       $
NLS_ISO_CURRENCY               AMERICA
NLS_NUMERIC_CHARACTERS           .,
NLS_CHARACTERSET               ZHS16GBK   (数据库字符集)
NLS_CALENDAR                       GREGORIAN
NLS_DATE_FORMAT                DD-MON-RR
NLS_DATE_LANGUAGE               AMERICAN
NLS_SORT                                  BINARY
NLS_TIME_FORMAT                HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT           DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT               HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT    DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY               $
NLS_COMP                           BINARY
NLS_LENGTH_SEMANTICS           BYTE
NLS_NCHAR_CONV_EXCP               FALSE
NLS_NCHAR_CHARACTERSET           AL16UTF16  (国家字符集)
NLS_RDBMS_VERSION               11.2.0.1.0


为什么我export NLS_LANG=AMERICAN_AMERICA.UTF8后,查看带有中文的表时,还是显示乱码
而export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK后中文却显示正常
但问题我的OS字符集是UTF8啊,不应该讲NLS_LANG设成UTF8吗?
标签: 暂无标签
Ashic

写了 1 篇文章,拥有财富 59,被 2 人关注

转播转播 分享分享 分享淘帖
回复

使用道具

P4 | 发表于 2014-6-15 21:19:25
额,沉了啊
回复

使用道具

P4 | 发表于 2014-6-16 08:54:43
回复

使用道具

P4 | 发表于 2014-6-16 09:00:11
谢谢分享。。。
回复

使用道具

P4 | 发表于 2014-6-17 22:11:32
甲骨论不行啊
回复

使用道具

P4 | 发表于 2014-6-18 03:27:56
字符集的问题主要是客户端系统和服务端数据库的字符集要一致,如果不一致,

要变成一致
实验:
初始环境Redhat5.5、Oracle 10.2.0.5
login as: oracle
oracle@192.16.16.10's password:
Server refused to set all environment variables
Last login: Tue Jun 17 22:59:00 2014 from 192.16.16.3
[oracle@sfwlinux ~]$ cd /oracle
[oracle@sfwlinux oracle]$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
[oracle@sfwlinux oracle]$ sqlplus / as sysdba

SQL*Plus: Release 10.2.0.5.0 - Production on Tue Jun 17 23:01:25 2014

Copyright (c) 1982, 2010, Oracle.  All Rights Reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bit

Production
With the Partitioning, OLAP, Data Mining and Real Application Testing

options

SQL> select * from nls_database_parameters;

PARAMETER                      VALUE
------------------------------

--------------------------------------------------------------------------------
NLS_LANGUAGE                   AMERICAN
NLS_TERRITORY                  AMERICA
NLS_CURRENCY                   $
NLS_ISO_CURRENCY               AMERICA
NLS_NUMERIC_CHARACTERS         .,
NLS_CHARACTERSET               ZHS16GBK
NLS_CALENDAR                   GREGORIAN
NLS_DATE_FORMAT                DD-MON-RR
NLS_DATE_LANGUAGE              AMERICAN
NLS_SORT                       BINARY
NLS_TIME_FORMAT                HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT           DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT             HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT        DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY              $
NLS_COMP                       BINARY
NLS_LENGTH_SEMANTICS           BYTE
NLS_NCHAR_CONV_EXCP            FALSE
NLS_NCHAR_CHARACTERSET         AL16UTF16
NLS_RDBMS_VERSION              10.2.0.5.0

20 rows selected.

SQL> create table test (a varchar2(32));

Table created.

SQL> insert into test values('中文');

1 row created.

SQL> commit;

Commit complete.

SQL> select * from test;

A
------------
??????
查询出来的都是乱码,这是因为数据库是ZHS16GBK,而系统是UTF-8的
1.将数据库的字符集改为和OS系统字符一致
目标:将数据库的字符集改为UTF8.
如果按照export NLS_LANGUAGE=AMERICAN_AMERICA.UTF8,结果效果没

出来。。
然后想到直接改数据库字符集
这个是有很大风险的,因为如果要改变字符集,new字符集需要是old字符集的超

集,
如果没有超级子集关系,需要强制转换,可能会造成数据的损坏,务必慎重!
本例从ZHS16GBK到UTF8的转换就是强制转换。
现在做个测试:
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount;
ORACLE instance started.

Total System Global Area 1845493760 bytes
Fixed Size                  2021568 bytes
Variable Size             452986688 bytes
Database Buffers         1375731712 bytes
Redo Buffers               14753792 bytes
Database mounted.
SQL> alter session set sql_trace=true;

Session altered.

SQL> alter system enable restricted session;

System altered.

SQL> alter system set job_queue_processes=0;

System altered.

SQL> alter system set aq_tm_processes=0;

System altered.

SQL> alter database open;

Database altered.

SQL> alter database character set INTERNAL_USE UTF8;
/******INTERNAL_USE 强制不检查是否超子集关系,否则此处会报
alter database character set utf8
*
ERROR at line 1:
ORA-12712: new character set must be a superset of old character set****/


Database altered.

SQL>update props$ set VALUE$='UTF8' where

NAME='NLS_NCHAR_CHARACTERSET'
SQL>commit;
然后重启数据库,shutdown immediate 再startup(不重启应该也可以,保险起

见重启)
SQL> select * from test;

A
------------
??????
原有的还是不能正常显示
SQL>insert into test values('我爱中文');
SQL>commit;
SQL>select * from test;

A
----------------------------------------------------------------
??????
我爱中文

最后再解释为什么以前的数据无法显示为中文

2.将OS中的UTF-8变成和数据库 ZHS16GBK一致
首先将环境再次切换到初始试验环境
①.通过中文环境下Windows 7下面的PL/SQL Developer访问数据库
select * from test;
?????
insert into test values('我是win7');
提交
我是Win7
由于客户端是win7中文,数据库也是ZHS16GBK,所以没有问题
②.如果非要钻牛角尖,说我要用redhat5.5既做服务器端又做客户端,
那就必须要将UTF-8改成和数据库一致了。
试验:
[oracle@sfwlinux ~]$ cd /oracle
[oracle@sfwlinux oracle]$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
[oracle@sfwlinux oracle]$ export

NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
[oracle@sfwlinux oracle]$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
[oracle@sfwlinux oracle]$ sqlplus / as sysdba
......
SQL>insert into test values('中文');
SQL>commit;
SQL>select * from test;

A
--------------------------------
??????
中文
这一步不是改数据库或者OS字符集,只是申明了一个环境变量
由于UTF-8包含了所有ZHS16GBK的字符,只是编码方式不一样。
所以此处没有将OS中的UTF-8改为中文字符集就已经实现了中文
的插入显示。
下面是在Linux下将UTF-8转为中文
[oracle@sfwlinux Oracle]#export LANG=zh_CN.GBK
[oracle@sfwlinux oracle]$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
这样就算结束了

如果要保持NLS_LANG持久,请写入vi ~/.bash_profile
export NLS_LANG=NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

回复

使用道具

P4 | 发表于 2014-6-20 21:39:12
shifouwan 发表于 2014-6-18 03:27
字符集的问题主要是客户端系统和服务端数据库的字符集要一致,如果不一致,

要变成一致

我就是不明白,相老师视频说,NLS_LANG应该和OS设置一样,
为什么设置一样了缺不能显示中文
回复

使用道具

P4 | 发表于 2014-6-22 22:10:12
首先你要搞清楚,set nls_lang改变的究竟是什么。。如果你是远程过去一个数据库,那么set nls_lang改变的就是你在用的客户端的字符集。如果你直接在服务端操作,那么nls_lang其实就是要改变你服务器端的字符集,目前数据库是ZHS16GBK的客户端好像必须是ZHS16GBK才能正常显示,所以你设置export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK有效,设置export NLS_LANG=AMERICAN_AMERICA.UTF8无效,我上面举例的看一下(有个地方说错了,“这一步不是改数据库或者OS字符集,只是申明了一个环境变量
由于UTF-8包含了所有ZHS16GBK的字符,只是编码方式不一样。
所以此处没有将OS中的UTF-8改为中文字符集就已经实现了中文
的插入显示。”)纠正一下,应该是改变了客户端字符集,只不过没有改变系统图形界面输出显示值。如果要将英文界面显示为中文,则要改lang。服务端字符集UTF8不影响客户端字符集。比如你远程用win7上的PLSQL developer(ZHS16GBK)登陆,打开数据库一样可以正常使用。建议,建库时默认语言选择:AL32UTF8
回复

使用道具

您需要登录后才可以回帖 登录 | 加入社区

本版积分规则

意见
反馈