Oracle字符集引发的几个问题,常见的就是汉字占多少个字节,其次就是字符集致使数据库启动失败以及索引失效等问题html
汉字占多少个字节?sql
select length('ABCDE中文字符串FG'),lengthb('ABCDE中文字符串FG') from dual;数据库
就能够知道,一个汉字占了几个字节,也能够查看数据库的字符集session
select * from nls_database_parameters where parameter ='NLS_CHARACTERSET';oracle
当NLS_CHARACTERSET=AL32UTF8时(UTF-8是变长编码,每一个Unicode代码点按照不一样范围,能够有1-3字节的不一样长度)
NLS_LENGTH_SEMANTICS=BYTE时,一个汉字表明三个字节
NLS_LENGTH_SEMANTICS=CHAR时,一个汉字表明一个字节
当NLS_CHARACTERSET=US7ASCII时(字符集为单字节)
NLS_LENGTH_SEMANTICS=BYTE时,一个汉字表明两个字节
NLS_LENGTH_SEMANTICS=CHAR时,一个汉字表明两个字节函数
Oracle与汉字问题相关的函数工具
注意:计算长度的几个方法区别以下:post
LENGTH(string1) 返回以字符为单位的长度.
LENGTHB(string1) 返回以字节为单位的长度.
LENGTHC(string1) 返回以Unicode彻底字符为单位的长度.
LENGTH2(string1) 返回以UCS2代码点为单位的长度.
LENGTH4(string1) 返回以UCS4代码点为单位的长度.测试
substr,substrb均为字符串截取函数,都带有三个参数,第一个参数为所要截取的字符串,第二个参数为strart(索引均从1开始),第三个参数为length。
substr是按照字来算的,而substrb()是按照字节来算的编码
关于substr,substrb的例子举例:
SQL> select substr('今天是个好日子',3,5) from dual;
----------
是个好日子
SQL> select substrb('今天是个好日子',3,5) from dual;
-----
天是
结论是substr是按照字来算的,而substrb()是按照字节来算的。看下面的例子:
SQL> select substr('abcdef',3,4) from dual;
----
cdef
SQL> select substrb('abcdef',3,4) from dual;
----
cdef
分析:对于字母来讲,substr与substrb做用时同样的,但对于汉字来讲,substr是按字来取值,而substrb是按字节来取值,当所取长度为奇数时,则自动舍弃最后一位字节。
相似的还有,
length与lengthb 长度计算函数
select length('你好') from dual ----output:2
select lengthb('你好') from dual ----output :4
Instr与Instrb 字符串查找函数 instr(原字符串,查的字符串,起始位置,第几个匹配) 返回字符串位置,找不到返回0 .
select instr('日日花前长病酒','花前',1,1) from dual ----output:3
select instrb('日日花前长病酒','花前',1,1) from dual ----output:7
Oracle字符集
安装数据库的时候能够设置字符集,不一样版本可能默认的字符集是不同的(以Oracle 9i为例子)
首先查看字符集:(注意:修改数据库字符集时必须谨慎,修改以前必定要为数据库备份。因为不能回退这项操做,所以可能会形成数据丢失或者损坏)
SQL> select name,value$ from props$ where name like '%NLS%'; NAME VALUE$ ------------------------------ ------------------------------ NLS_LANGUAGE AMERICAN NLS_TERRITORY AMERICA NLS_CURRENCY $ NLS_ISO_CURRENCY AMERICA NLS_NUMERIC_CHARACTERS ., NLS_CHARACTERSET US7ASCII NLS_CALENDAR GREGORIAN NLS_DATE_FORMAT DD-MON-RR NLS_DATE_LANGUAGE AMERICAN ………………. NLS_NCHAR_CHARACTERSET AL16UTF16 NLS_RDBMS_VERSION 9.2.0.4.0 20 rows selected. SQL> select name,dump(name) from eygle.test; NAME DUMP(NAME) ------------------------------------------------------ 测试 Typ=1 Len=4: 178,226,202,212 Test Typ=1 Len=4: 116,101,115,116 2 rows selected.
转换字符集,你只能在新字符集是旧字符集严格超集的状况下使用这种方式转换。所谓超集是指:当前字符集中的每个字符在新字符集中均可以表示,并使用一样的代码点好比不少字符集都是US7ASCII的严格超集.
若是不是超集,将得到如下错误:
转换字符集,数据库应该在RESTRICTED模式下进行:
这时候,咱们能够去查看alert<sid>.log日志文件,看CLOB字段存在于哪些表上:
对于不一样状况,Oracle提供不一样的解决方案,若是是用户数据表,通常咱们能够把包含CLOB字段的表导出,而后drop掉相关对象,
转换后再导入数据库;对于系统表,能够按照如下方式处理:
在9.2.0中,转换完成之后,能够经过运行catmet.sql脚原本重建Metastylesheet表:
SQL> @?/rdbms/admin/catmet.sql
经过Metastylesheet表来测试不一样字符集的影响。
提示:
经过设置sql_trace,咱们能够跟踪不少数据库的后台操做,这个工具是DBA经常使用的“利器”之一。
咱们简单看一下数据库更改字符集时的后台处理,我提取了主要的更新部分。
经过如下跟踪过程,咱们看到数据库在更改字符集的时候,主要更新了12张数据字典表,修改了数据库的原数据,这也证明了咱们之前的说法:
这个更改字符集的操做在本质上并不转换任何数据库字符,只是简单的更新数据库中全部跟字符集相关的信息。
注意:经过前面 ” ALTER DATABASE CHARACTER SET” 方式更改字符集时,Oracle至少须要更改12张数据字典表,而这种直接更新props$表的方式只完成了其中十二分之一的工做,潜在的完整性隐患是可 想而知的。并且经过更新props$表的方式修改字符集,在Oracle7以后就不该该被使用.