1. 概念篇 1.1 什么是字符集? 字符集是字符(包含字母,数字,符号和非打印字符等)以及所指定的内码所组成的特定的集合。通常一个字符集包含一个字母表中的字符,例如拉丁字母表被使用在英语语言中,那么如果要使用拉丁字符,就要配置使用英语语言集中的特定的字符集合――拉丁语言字符集。这里为什么特指了是英语语言集呢?因为字符集是基于某种操作系统平台和某种语言集支持的。语言集的集合被称为语言组,它可能包含一种或多种语言。本地字符集是基于特定语言组中所包含的一种或多种语言支持的,在特定操作系统平台上编码的集合。
在Client/Server系统中,支持多语言的数据处理,但是所有的语言必须属于同一个语言组。例如,从下表可以看出,如果服务器中的数据用组1中的字符集,则同一数据库中可以有法语,德语,英语以及该组中的其它语言。而在这个数据库中就不能同时存储日语,法语了。
这里请注意一个非常特别的字符集—Unicode—它支持世界上超过650种语言的国际字符集。Unicode允许在同一服务器上混合使用不同语言组的不同语言。
表1-1 Adaptive Server支持的语言和字符集

注意:表中所显示的所有字符集,因为任何字符集的前128(十进制)个字符都包含拉丁字母表,所以所有字符集都支持英语。各字符集中前128个字符之外的字符各不相同,用于支持不同的本地语言字符。
1.2 什么是排序顺序? 每种字符集都有一种或多种排序顺序,Adaptive Server使用它们存储数据。排序顺序与特定的语言或语言组及特定的字符集联系密切,不同的语言对同样字符的排序是不同的,因此,需要特定语言的排序顺序,以便正确地对字符进行排序。另外,排序顺序与特定地字符集也密切相关,对于特定字符集可使用的排序顺序位于字符集目录的排序顺序定义的文件中(.srt文件)。 有关字符集及其可用排序顺序的列表,如下所示: 表1-2可用的排序顺序

排序顺序用于 ――创建索引 ――将数据存入按索引排序的表 ――指定order by子句
对于不同类型排序顺序的解释 二进制排序顺序: 对于所有字符集都至少提供一个二进制排序顺序,这一排序顺序基于字符集中分配给代表每个字符的代码(“二进制”代码)的算数值,适用于每个字符集的前128个字符和亚洲语言。当字符集支持一种以上的语言时,二进制排序顺序将会得出不正确的结果,这时就应该选择其它排序顺序了。
字典排序,区分大小写,区分重音: 分别对大写和小写字母进行排序。字典排序顺序识别字母的各种重音形式,并将它们排在相关联的非重音字母之后。
字典排序,不区分大小写,区分重音: 按字典顺序排序,大写字母与小写字母等同,在排序结果中大小写字母混合使用。对于避免表中名称的重复条目很有用。
字典排序,不区分大小写,区分重音,具有优先级: 在排序时不区分大小写,在所有其它条件相同时,大写字母具有高的优先级(即大写字母先出现)。
当order by子句中指定的列与表的聚簇索引键值相匹配时,使用这种排序顺序可能导致大表性能降低,因此,不建议使用这种排序顺序,除非特意要求大写字母排在小写字母之前。
字典排序,不区分大小写,不区分重音: 将加重音格的字母与未加重音格的相关联字母同等对待,它在排序中混合了重音字符。
1.3 什么是字符集转换? 为保持客户端与服务器之间的数据完整性,数据必须在字符集之间进行转换,目的是跨机器和字符集使用时,确保“a”还是“a”,此过程就是字符集转换。
字符集转换的方式 本地字符集的转换: Adaptive Server支持属于同一语言组的本地字符集之间的转换。如果服务器把一种本地字符集作为它的缺省值,则客户端字符集必须属于同一个语言组,此时可以在服务器上浏览所有客户端提交的数据。如下图:
图1-3 服务器端和客户端字符集属于同一语言组
本图中,服务器端与客户端使用的语言集与字符集都同属于组1(见表1-1),那么他们之间实现的就是本地字符集转换方式。
Unicode系统中的转换方式: 在Unicode系统中,由于服务器的缺省字符集为UTF-8,所以客户端字符集可以是任何语言组中的一种本地字符集。如下图:
图1-4Unicode系统中的字符集转换
 上图中来自每一个客户端的数据经过服务器和每个客户端时,都会被正确转换,而无论每一个客户端选择的时哪个语言组的字符集,原因是ASE服务器端选择了缺省字符集UTF-8.
字符集转换类型 直接转换: 支持同一语言组内两种本地字符集之间的转换。例如,Adaptive Server支持CP437与CP850之间的转换,因为他们同属于第1语言组。
Unicode转换: Unicode转换可应用于所有本地字符集,在两种本地字符集之间进行转换时,Unicode转换方式把Unicode作为中间字符集。例如,在服务器缺省字符集CP437和客户端字符集CP860之间进行转换时,CP437先被转换成Unicode,Unicode再转换成CP860。
Unicode转换方式既可以用于服务器缺省字符集UTF-8,还可用于本地字符集。除非使用服务器缺省字符集UTF-8,否则您必须专门配置您的服务器才能使用Unicode转换方式(配置方法请参看配置篇之如何配置字符集的转换类型)。
如何选择字符集的转换方式 这将取决于系统的类型。
在非Unicode系统中,服务器和客户端的字符集为本地字符集,因此可以使用Adaptive Server直接转换,但是有些字符集没有直接转换,这种情况就必须使用Unicode转换了。
如下表所示: 表1-5 字符集转换方式  ――如果系统中使用的所有字符集都在表1-5的列1中,则使用直接转换。前提是所有字符集同属于一个语言组。 ――如果系统中使用的所有字符集都在表1-5的列2中,或者有些在列1中,有些在列2中,那么必须配置服务器使用Unicode转换方式。前提是所有字符集同属于一个语言组。
在Unicode系统中,如果服务器缺省字符集为Unicode UTF-8,那么所有的转换将在UTF-8与客户端使用的本地字符集之间进行,因此,在Unicode系统中,只能使用Unicode转换。
2. 配置篇 2.1 如何配置字符集的转换类型 禁用字符集转换的配置方法 在isql环境中执行: 1> sp_configure “disable character set conversion”,1 2> go “disable character set conversion”参数默认配置值为0,即启用字符集转换。
如何配置字符集的转换类型 把”enable unicode conversions”参数设置为1或者2。当配置为1时,此设置使用直接转换或Unicode转换;当配置为2时,此设置使用Unicode转换;默认配置值为0,使用直接转换。
在isql环境中执行: 1> sp_configure ”enable unicode conversions”,1 2> go
2.2 如何配置服务器端缺省字符集 直接转换法 直接转换法是指直接使用Sybase提供的实用程序,如UNIX平台上使用sqlloc命令或者编辑sqlloc.rs脚本文件;Windows平台使用“服务器配置”图形化管理工具直接配置服务器端字符集。
使用直接转换法的条件是: ――服务器中没有用户数据 ――对服务器中用户数据的损坏是可以接受的 ――绝对确定服务器中的数据只使用ASCII-7字符集
间接转换法 间接转换法相对于直接转换法而言,需要通过一下三步来完成配置工作: 1. 先将服务器端的数据使用bcp命令导出 2. 再选择直接转换法之中的一种方式配置服务器端字符集 3. 再使用带有-J 参数的bcp命令把数据导回服务器端
配置服务器端字符集的方法 sqlloc—适用于UNIX平台的命令 在$SYBASE_OCS/bin目录下执行:sqlloc,将出现一个图形化界面,在这个界面中您可以直接选择语言集,字符集,排序顺序,便很容易地就完成了配置工作。
编辑sqlloc.rs脚本文件 将$SYBASE-ASE/init/sample_resource_files/sqlloc.rs拷贝到$SYBASE_OCS/bin目录下,按以下黑体字提示编辑该文件: sybinit.release_directory: /home/sybase―――输入Sybase产品的安装路径 sqlsrv.server_name: SYB125―――输入数据库服务器的名称 sqlsrv.sa_login: sa sqlsrv.sa_password: ―――输入sa的口令,若为空,则什么也不填 sqlsrv.default_language: us_english―――输入想要配置的语言集 sqlsrv.language_install_list: USE_DEFAULT sqlsrv.language_remove_list: USE_DEFAULT sqlsrv.default_characterset: cp850―――输入想要配置的字符集 sqlsrv.characterset_install_list: USE_DEFAULT sqlsrv.characterset_remove_list: USE_DEFAULT sqlsrv.sort_order: binary―――输入想要配置的排序顺序 # An example sqlloc resource file... # sybinit.release_directory: USE_DEFAULT # sqlsrv.server_name: PUT_YOUR_SERVER_NAME_HERE # sqlsrv.sa_login: sa # sqlsrv.sa_password: # sqlsrv.default_language: french # sqlsrv.language_install_list: spanish,german # sqlsrv.language_remove_list: USE_DEFAULT # sqlsrv.default_characterset: cp437 # sqlsrv.characterset_install_list: mac,cp850 # sqlsrv.characterset_remove_list: USE_DEFAULT # sqlsrv.sort_order: dictionary
保存已经修改好的sqlloc.rs脚本文件,执行以下命令: sqllocres -r sqlloc.rs
注意屏幕上出现的提示信息,如无异常,则完成配置工作。
“服务器配置”图形化管理工具――适用于Windows平台 “服务器配置”管理工具提供了一个易于操作的图形化管理平台,根据工具中提示的信息,很容易就完成了字符集的配置工作,这里就不多讲了,请参看相关文档说明。
2.3 如何配置客户端缺省字符集 配置客户端缺省字符集实际上就是对“$SYBASE\locales”目录下locales.dat文件的修改。
Windows平台用写字板方式打开该文件,在UNIX平台可以直接使用“vi”命令打开该文件,我们会看到,该文将中所有字符集的配置都是以服务器端操作系统平台名称分组的: . . [aix] locale = C, us_english, iso_1 locale = En_US, us_english, iso_1 locale = en_US, us_english, iso_1 locale = default, us_english, iso_1 locale = En_US.IBM-850, us_english, cp850 locale = en_JP, us_english, eucjis locale = Fr_FR, french, cp850. . [axposf] locale = C, us_english, iso_1 ; Use Posix Locales, straight from the Posix Guidelines locale = en_US.88591, us_english, iso_1 locale = fr_FR, french, iso_1 locale = zh_CN, chinese, eucgb locale = zh_TW, tchinese, euccns locale = ko_KR, korean, eucksc locale = us_english.utf8, us_english, utf8 locale = default, us_english, iso_1 . . 其中,操作系统名称放在每一组最开始的“[]”中,而且请注意上面黑体字,每一组中都会存在一行“locale = default,…”。我们要修改客户端的默认字符集,就是对这一行进行修改。
例如,某系统服务器端是SUN平台,服务器端语言集为english,字符集为cp850。我们要修改客户端字符集与服务器端一致,怎么做? 首先找到[SUN]操作系统分组,然后修改“locale = default,…”为“locale = default,us_English,cp850”。 修改前: [sun] ; from JLE, KLE, CLE, OS/4.1.1, man setlocale() ; and Sun Software Internationalization Guide (p/n 800-5972-08) ; use setenv LC_CTYPE, LC_MESSAGES, LANG locale = C, us_english, iso_1 locale = fr, french, iso_1 locale = de, german, iso_1 locale = tr, us_english, iso88599 locale = zh, chinese, eucgb locale = zh_CN, chinese, eucgb locale = zh_TW, tchinese, euccns locale = ko, korean, eucksc locale = us_english.utf8, us_english, utf8 locale = default, us_english, iso_1
修改后: [sun] ; from JLE, KLE, CLE, OS/4.1.1, man setlocale() ; and Sun Software Internationalization Guide (p/n 800-5972-08) ; use setenv LC_CTYPE, LC_MESSAGES, LANG locale = C, us_english, iso_1 locale = fr, french, iso_1 locale = de, german, iso_1 locale = tr, us_english, iso88599 locale = zh, chinese, eucgb locale = zh_CN, chinese, eucgb locale = zh_TW, tchinese, euccns locale = ko, korean, eucksc locale = us_english.utf8, us_english, utf8 locale = default, us_english, cp850
保存该文件,就完成对客户端字符集的修改了。
这里,还要说明一种特殊情况: 为了满足服务器端某些应用的特殊需求,在服务器端设置了一个环境变量:LANG,此时客户端字符集该如何设置呢?
例如,某系统服务器端是Windows平台,使用语言集english,字符集iso_1,并设置环境变量LANG=C。我们要修改客户端字符集与服务器端一致,怎么做?
首先找到[NT]操作系统分组,然后在该组中加入一行 “locale = C,us_English,iso_1” 修改前: [NT] locale = enu, us_english, iso_1 locale = fra, french, iso_1 locale = deu, german, iso_1 locale = japanese, japanese, sjis locale = chs, chinese, eucgb locale = cht, tchinese, big5 ; locale = kor, korean, eucksc locale = us_english.utf8, us_english, utf8 locale = default, us_english, iso_1
修改后: [NT] locale = enu, us_english, iso_1 locale = fra, french, iso_1 locale = deu, german, iso_1 locale = japanese, japanese, sjis locale = chs, chinese, eucgb locale = cht, tchinese, big5 ; locale = kor, korean, eucksc locale = us_english.utf8, us_english, utf8 locale = default, us_english, iso_1 locale = C,us_English,iso_1 因此在修改客户端字符集之前,请先查看服务器端是否设置了环境变量“LANG“,再决定如何修改。
2.4 如何选择ASE字符集使之支持简体中文字符 目前在ASE 12.5中支持中文字符的字符集有四种:CP936,EUCGB,UTF-8和GB18030。
其中EUCGB字符集是基于GB2312-80编码规范的,它的EUC (Extended Unix Code)编码范围是第一字节0xA1~0xFE(实际只用到0xF7),第二字节0xA1~0xFE。
CP936字符集是基于GBK编码规范(实际上的国家标准是GB13000-90),是对GB2312进行的扩展,第一字节为0x81~0xFE,第二字节分两部分,一是0x40~0x7E,二是0x80~0xFE。其中和GB2312相 同的区域,字完全相同。
GB18030字符集(国家标准号是GB18030-2000)是2000年3月17日发布的新的中文编码标准。它是GB2312的扩充,采用单/双/四字节编码体系结构,收录了27000多个汉字以及臧文、蒙文、维吾尔文等主要的少数民族文字。Sybase 从ASE 12.5.0.3之后开始支持GB18030字符集。
UTF-8字符集是现有ASCII系统向Unicode转换的一个过渡方案。它使用1-3字节表示一个字符。简体中文的每个字符在utf8中的长度基本上都是3个字节。它的最主要的优点是可以同时支持超过650种语言的字符。缺点是针对中文字符来说,需要增加50%的空间用来存储。还有一个问题是执行sp_helptext显示存储过程体的时候,有可能出现半个汉字。
一般来说,由于EUCGB不支持国标一、二级字库以外的汉字,所以我们推荐用户在服务器端和客户端都使用CP936字符集,或者在ASE 12.5.0.3之后还可以使用GB18030字符集,它可以支持一些比较生僻的汉字。它的不足是只有一种排序方式,即区分大小写的Binary方式。所以,如果需要使用支持中文字符集且不区分大小写的数据库时,就只能使用UTF-8作为服务器端字符集,而客户端使用CP936或GB18030字符集。
另外,还有一种选择是,服务器端和客户端都使用iso_1字符集,虽然iso_1字符集并不直接支持中文字符,但我们将服务器端和客户端都设置成iso_1字符集后,系统也不会在客户端和服务器端进行字符转换,它只不过将一个汉字的两个字节当做两个单独字符来处理,一般情况下没有问题。但当执行like匹配查询的时候,它有可能返回不正确的结果,原因是服务器端是根据单字节去匹配查询条件的,很可能会有前一个汉字的第二字节与后一个汉字的第一字节的内码组合符合查询条件,被服务器端作为查询结果返回来。
2.5 如何查看服务器端、客户端字符集 查看服务器端字符集: 在isql环境中执行: 1> sp_helpsort 2> go 查看客户端字符集: 在isql环境中执行: 1> select @@client_csname 2> go
3. 错误处理篇 3.1 为什么会出现字符集转换失败 1. 当字符存在于客户端字符集中但在服务器字符集中不存在时,Adaptive Server的字符集转换将报告转换错误,反之亦然。 用户会碰到下面的错误消息: Msg 2402,Severity 16 (EX_USER): Error converting client characters into server's character set. Some character(s) could not be converted. 转换错误会阻止插入与更新语句的执行。如果发生此情况,请检查数据中有问题的字符并替换它们。
2. 当客户端发送数据时Adaptive Server遇到转换错误,它用ASCII码的问号(?)代替可疑字符所占字节,但查询批处理继续进行直到完成为止。 语句完成后,Adaptive Server将发送一下消息: Msg 2403,Severity 16 (EX_USER): WARNING! Some character(s) could not be converted into client's character set. Unconverted bytes were changed to question marks (`?')。
3. 当在客户端查询服务器端存储的数据时,当碰到中文汉字,在客户端显示乱码的现象,且没有任何提示信息。 这是我们在应用中经常会碰到的现象,产生的原因是:客户端与服务器端字符集不符。怎么解释呢?假设我们先期设置服务器端字符集为iso_1,客户端字符集也为iso_1,然后我们从客户端向服务器端录入了所有的数据;之后当我们需要查询时,使用的客户端,它的字符集为cp850,那么势必在该客户端上显示的字符集为乱码。
当出现这种情况时,最好配置客户端字符集为先期客户端使用的字符集或者配置客户端字符集与服务器端字符集一致,使得客户端字符集与服务器端字符集匹配。这里我们不建议用户修改服务器端字符集,因为服务器中此时已经存在大量的数据,在使用直接转换方式时,由于源字符集与目的字符集中可能存在无法转换的字符而导致Adaptive Server无法启动;如果使用间接的转换方式,会增加工作量。
4. 附:如何安装cp936字符集 以在Windows平台安装cp936字符集为例,说明如何安装使用服务器中没有被默认安装的字符集。(在ASE 12.5.0.3版本中安装GB18030字符集的方法类似) (这里SYBASE的安装路径为c:\sybase) 1.c:\>cd \sybase\charsets\cp936 2.c:\sybase\charsets\cp936> charset -Usa -Psa_pass -Sserver_name binary.srt cp936 3.在SQL环境中 1>select name,id from syscharsets 2>go 找到name为cp936对应的id(假设为171) 4.1>sp_configure "default character set id",171 2>go
5.重启server两次 (注:第一次启动后,server会自动宕掉,需要第二次重启后才能使用) |