oracle字符集及编码知识

摘要:
1,双字节字符集ZHS16GBK中,则一个中文汉字是一个字符,一个英文字母也是一个字符,所以他们俩占的存储空间一样大!
2,字符集就是一套编码规则。 eg:在字符集charset1中 A、B、? 的编码分别为 A(0001),B(0010),?(1111);
3,查看oracle 字符集 SQL> SELECT NAME,VALUE$ FROM SYS.PROPS$ WHERE NAME='NLS_CHARACTERSET';
4,查看客户端(即操作系统)的字符集 export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

六、修改了错误的字符集,oracle是怎么处理的?


两个基本原则:
在数据库端:选择需要的字符集(通过create database中的CHARACTER SET与NATIONAL CHARACTER SET子句指定);
在客户端:设置操作系统实际使用的字符集(通过环境变量NLS_LANG设置)

.



一、编码知识:

根据一个字符需要多少位字节来表示,可以把字符集分为单字节字符集和多字节字符集。其中,单字节字符集又分为7位字符集和8位字符集。单字节7位编码字符集有US7ASCⅡ,单字节8位编码字符集有符合ISO 8859-1标准规定的WE8ISO8859P1等。多字节编码又分为固定长度(长度大于或等于2)编码模式和不固定长度编码模式。多字节编码字符集中的ZHS16GBK、ZHS16CGB231280、JA16SJIS等是采用两个字节表示一个字符的字符集,又叫双字节字符集。


一个英文字母是一个字符,一个中文汉字是几个字符呢?我们知道,一个中文汉字是双字节字符,但它有几个字符与其数据库字符集有关。如果数据库字符集使用单字节US7ASCII,则一个中文汉字是二个字符;如果数据库字符集使用双字节字符集ZHS16GBK,则一个中文汉字是一个字符。一个英文字母也是用两个字节(一个字符)来表示!;在单字节字符集中,一个汉字需要两个字符,一个英文字母需要一个字符!有关这一点可以使用Oracle的函数Substr得到证明。


使用US7ASCⅡ字符集时:


Select substr('西安邮电',1,2) from dual;

语句执行结果返回 '西'。


使用ZHS16GBK字符集时:


Select substr('西安邮电',1,2) from dual;

语句执行结果返回'西安'






二、碰到的问题:

欧衡山突然跑来跟我说:他往表里面写数据写不进去了,说是超出了存储范围。建的表字段是varchar2(4000) ,往里面写的数据只有2000个英文字符,怎么就写不进去了呢?

很显然系统用了两个字节来存储一个英文字母!



分析解决问题:

SQL> SELECT NAME,VALUE$ FROM SYS.PROPS$ WHERE NAME='NLS_CHARACTERSET';


NAME                  VALUE$

------                    --------

NLS_CHARACTERSET      ZHS16GBK

说明:多字节编码字符集中的ZHS16GBK、ZHS16CGB231280、JA16SJIS等是采用两个字节表示一个字符的字符集,又叫双字节字符集。

数据库字符集使用双字节字符集ZHS16GBK,则一个中文汉字是一个字符,一个英文字母也是一个字符!

.




三、什么是字符集

字符集就是一套编码规则。 用下面的例子说明问题

在字符集charset1中 A、B、? 的编码分别为 A(0001),B(0010),?(1111);

在字符集charset2 中 A、B、? 的编码分别为 A(1001),C(1010),?(1111);

其中的数字就是给计算机看的。我们可以写一个程序实现charset1和charset2的相互转换。由于知道两个字符集的编码规则,对于demo_charset1中的0001,在转换为demo_charset2时,要将其编码改为1001;对于demo_charset1中的1111,转换为demo_charset2时,其数值不变;而对于demo_charset1中的0010,其对应的字符为B,但在demo_charset2没有对应的字符,所以从理论上无法转换,对于所有这类无法转换的情况,我们可以将它们统一转换为目标字符集中的一个特殊字符(称为“替换字符”),比如在这里我们可以将?作为替换字符,所以B就转换为了?,出现了信息的丢失;同样道理,将demo_charset2的C字符转换到demo_charset1时,也会出现信息丢失。(红色字体部分很重要,这就是我们平时碰到的乱码问题的根本原因。如果我们将汉字编码GBK转换为只有英文编码的USA7ASCII的时候,由于USA7ASCII里面没有类似例子中"B"的编码存在,所以就用"?"代替了。)
所以说,在字符集转换过程中,如果源字符集中的某个字符在目标字符集中没有定义,将会出现信息丢失。
.


四、数据库应该选择怎样的字符集


如果选错字符集会有什么麻烦

如过我们用WE8ISO8859P1或US7ASCII(美国标准字符集)来存储汉字,而这两个字符集都没有汉字编码,所以用这种字符集存储汉字信息从原则上说就是错误的。虽然在有些时候选用这种字符集好象也能正常使用,但它会给数据库的使用与维护带来一系列的麻烦!

.




五、如何修改数据库和客户端字符集

更改服务器字符集为ZHS16GBK (其实这是非常规做法,会引起很多问题)
SQL> update props$ set value$='ZHS16GBK' WHERE NAME='NLS_CHARACTERSET';
1 row updated.
SQL> COMMIT;
我们应该先将数据库export出来,然后trucate掉所有数据,修改字符集,最后import进数据!


更改客户端字符集为ZHS16GBK
# export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

NLS_LANG的格式如下:

NLS_LANG=<Language>_<Territory>.<Clients Characterset>

NLS_LANG各部分含义如下:

    Language
        -Oracle消息使用的语言
        -日期中月份和日显示

    Territory
        -货币和数字格式
        -地区和计算星期及日期的习惯

    Clients Characterset
        -控制客户端应用程序使用的字符集

.

六、修改了错误的字符集,oracle是怎么处理的

.

如果你设置了一个不存在的字符集,那么oracle重启后会自动update为缺省的字符集US7ASCII
实验过程:
list1:查看当前字符集
SQL> select value$ from props$ where name='NLS_CHARACTERSET';

VALUE$
-----
ZHS16GBK

.

lisnt2:修改字符集:
SQL> update props$ set value$='ZHENGBIN'
2 where name='NLS_CHARACTERSET';

1 row updated.

SQL> commit;

Commit complete.

.

list3:重启oracle后在警告日志里看到下面的信息

Wed Jul 22 16:01:21 2009
Updating character set in controlfile to US7ASCII
Wed Jul 22 16:01:21 2009

参考文档:

http://www.blogjava.net/zamber/archive/2006/09/25/71757.html

http://www.itpub.net/276524.html

http://www.eygle.com/archives/2006/06/dba_update_prop.html

站内:

http://hi.baidu.com/bkeep/blog/item/d9bbba88e2347cba0f244482.html

http://hi.baidu.com/bkeep/blog/item/64c308ebfaa145dad539c995.html

http://hi.baidu.com/bkeep/blog/item/ad2e10088eafef8bd1581b96.html

你可能感兴趣的:(oracle)