关于 Db2 character set collation

说明

  本文总结了 Db2 在不同字符集(character set)和校对(collation)设置情况下的排序和比较行为。下面的标题表示在 CREATE DATABASE 语法中的指定。

  根据参考9,如果创建数据库的时候没有指定 COLLATE USING,那么默认的 collate 是 system,规则如下:
For non-Unicode databases, the collating sequence is based on the database territory. For Unicode databases, this parameter maps to a language-aware collation, based on the client code set and territory. If an appropriate language-aware collation is turned off, then the IDENTITY collation is used.

  创建数据库的时候也可以指定某一种特定的 collate,对于 Unicode 字符集的数据库来说,Db2 提供了三种 collate:IDENTITY collation, language-aware collation, 和 locale-sensitive UCA-based collation.(参考10)

using codeset GBK territory CN

  非 Unicode 字符集,不指定 collation 的情况下,默认是 system,collation 由 codeset 和 territoy 决定,这里 territoy 是 CN,根据参考1,使用 SYSTEM_1386(参考2),表示单级比较,先比较字母顺序,再比较大小写,这里字母 j 的顺序在 J 的前面,因此排序是这样的:

db2 get db cfg for test1|grep -i "collating sequence"
 Database collating sequence                             = UNIQUE

db2 "select * from test1 order by c1"

C1        
----------
china     
China     
j2        
j6        
J2        
J6        

  6 record(s) selected.

using codeset GBK territory CN collate using identity

  非 Unicode 字符集,指定 collation 是 identity,也就是按照 codeset 编码,这时候根据 GBK 码表,大写在小写的前面,也就是:

db2 get db cfg for test2|grep -i "collating sequence"
 Database collating sequence                             = IDENTITY

db2 "select * from test2 order by c1"

C1        
----------
China     
J2        
J6        
china     
j2        
j6        

  6 record(s) selected.

注:GBK identity 和 MySQL 的 gbk_bin 排序结果是一样的。

using codeset UTF-8 territory CN

  Unicode 字符集,不指定 collation 的情况下,默认会根据 client codeset 和 territory 决定(文章第二段阐述的规则),假设 client codeset 也是 Unicode,根据参考3,collation 是 identity,因此根据 UTF-8 码表,大写在小写的前面,于是排序是:

db2 get db cfg for test2|grep -i "collating sequence"
 Database collating sequence                             = IDENTITY

db2 "select * from test3 order by c1"

C1        
----------
China     
J2        
J6        
china     
j2        
j6        

  6 record(s) selected.

注:UTF-8 identity 和 MySQL 的 utf8mb4_bin 排序结果是一样的。

using codeset UTF-8 territory CN collate using SYSTEM_1386_CN

  Unicode 字符集,指定了 language-aware-collation 为 SYSTEM_1386_CN,就会按照参考2 进行排序,先比较字母顺序,再比较大小写,也就是:

db2 get db cfg for test4|grep -i "collating sequence"
 Database collating sequence                             = SYSTEM_1386

db2 "select * from test3 order by c1"

C1        
----------
china     
China     
j2        
j6        
J2        
J6        

  6 record(s) selected.

using codeset UTF-8 territory CN collate using CLDR2701_LZH_KUNIHAN

  Unicode 字符集,指定了 locale-sensitive-collation 为 CLDR2701_LZH_KUNIHAN,根据参考4,知道这是一种 UCA 算法(多级排序),默认的排序规则是 CLDR2701_LZH_KUNIHAN_AN_CX_EX_FX_HX_NX_S3,输出是这样的:

db2 get db cfg for test5|grep -i "collating sequence"
 Database collating sequence                             = CLDR2701_LZH_KUNIHAN_AN_CX_EX_FX_HX_NX_S3

db2 "select * from test3 order by c1"

C1        
----------
china     
China     
j2        
J2        
j6        
J6        

  6 record(s) selected.

  可以看到,这是和 SYSTEM_1386 以及 identity 都不同的一种排序方式,这是因为属性 CLDR2701_LZH_KUNIHAN_AN_CX_EX_FX_HX_NX_S3 中的 S3 表示不忽略重音符和大小写,EX 表示关闭大小写级别,CX 表示如果字符串没有其他差别,那么是小写优先,这些属性组合在一起便是:
  S3 区分大小写,EX 不区分大小写,于是区分大小写,因为没有其他差别,根据小写优先,所以 china 在 China 的前面,j2 在 J2 的前面,j6 在 J6 的前面。
  注意这里非常重要的一点是,为什么小写优先,而 J2 会在 j6 的前面呢?这是因为 UCA 算法是多级比较(Multi-Level Comparison,参考5 和参考6),通俗地讲就是先不考虑大小写和重音,比较两个字符串里的字符,其次才根据是否忽略大小写和重音的属性规则来进行排序。

使用 COLLATION_KEY_BIT 进行调整和测试

  如上述,我们知道了 Db2 数据库在创建伊始就决定了排序方式,后续是无法更改的,但是有一个变通的方法是使用 COLLATION_KEY_BIT 函数可以显式指定一种 collation,这里可以指定 Unicode Collation Algorithm-based collations 或者 language-aware collations for Unicode data,它可以在任何一种数据库中操作,因此可以方便地进行验证和测试,这里举几个例子:

  1. 我们在一个 using codeset GBK territory CN 的数据库中进行操作,这显然不是一个 UCA 算法的数据库,正如第一小节所描述的,正常情况下,排序和比较应该是这样的:
db2 "select * from test1 order by c1"

C1        
----------
china     
China     
j2        
j6        
J2        
J6        

  6 record(s) selected.

db2 "select * from sysibm.sysdummy1 where 'a'='A'"

IBMREQD
-------

  0 record(s) selected.
  1. 使用 S1 不区分重音和大小写,使用 EX 不区分大小写,结果是不区分大小写:
db2 "select * from sysibm.sysdummy1 where COLLATION_KEY_BIT('a','CLDR2701_LZH_KUNIHAN_S1_EX')=COLLATION_KEY_BIT('A','CLDR2701_LZH_KUNIHAN_S1_EX')"

IBMREQD
-------
Y      

  1 record(s) selected.
  1. 用 S1 不区分重音和大小写,使用 EO 区分大小写,结果是区分大小写:
db2 "select * from sysibm.sysdummy1 where COLLATION_KEY_BIT('a','CLDR2701_LZH_KUNIHAN_S1_EO')=COLLATION_KEY_BIT('A','CLDR2701_LZH_KUNIHAN_S1_EO')"

IBMREQD
-------

  0 record(s) selected.
  1. S2 和 S1 的差别仅在重音,大小写方面没有差别,测试结果也完全一样:
db2 "select * from sysibm.sysdummy1 where COLLATION_KEY_BIT('a','CLDR2701_LZH_KUNIHAN_S2_EX')=COLLATION_KEY_BIT('A','CLDR2701_LZH_KUNIHAN_S2_EX')"

IBMREQD
-------
Y      

  1 record(s) selected.

db2 "select * from sysibm.sysdummy1 where COLLATION_KEY_BIT('a','CLDR2701_LZH_KUNIHAN_S2_EO')=COLLATION_KEY_BIT('A','CLDR2701_LZH_KUNIHAN_S2_EO')"

IBMREQD
-------

  0 record(s) selected.
  1. 使用 S3 区分重音和大小写,使用 EX 不区分大小写,结果是区分大小写:
db2 "select * from sysibm.sysdummy1 where COLLATION_KEY_BIT('a','CLDR2701_LZH_KUNIHAN_S3_EX')=COLLATION_KEY_BIT('A','CLDR2701_LZH_KUNIHAN_S3_EX')"

IBMREQD
-------

  0 record(s) selected.
  1. 使用 S3 区分重音和大小写,使用 EO 区分大小写,结果是区分大小写:
db2 "select * from sysibm.sysdummy1 where COLLATION_KEY_BIT('a','CLDR2701_LZH_KUNIHAN_S3_EO')=COLLATION_KEY_BIT('A','CLDR2701_LZH_KUNIHAN_S3_EO')"

IBMREQD
-------

  0 record(s) selected.
  1. 使用 CU 大写优先,注意这里依然是多级比较:
db2 "select * from test1 order by COLLATION_KEY_BIT(c1,'CLDR2701_LZH_KUNIHAN_CU')"

C1        
----------
China     
china     
J2        
j2        
J6        
j6        

  6 record(s) selected.
  1. 使用 CL 小写优先,注意这里依然是多级比较:
db2 "select * from test1 order by COLLATION_KEY_BIT(c1,'CLDR2701_LZH_KUNIHAN_CL')"

C1        
----------
china     
China     
j2        
J2        
j6        
J6        

  6 record(s) selected.
  1. 不管是 CU 还是 CL,至少要开启区分大小写,如果都关闭((S1 或 S2) 且 EX),那么对于相同的字符串,大写或是小写在前面都是合理的,会按照输入(INSERT)的顺序排序输出:
db2 "select * from test1 order by COLLATION_KEY_BIT(c1,'CLDR2701_LZH_KUNIHAN_S1_EX_CU')"

C1        
----------
china     
China     
J2        
j2        
j6        
J6        

  6 record(s) selected.

db2 "select * from test1 order by COLLATION_KEY_BIT(c1,'CLDR2701_LZH_KUNIHAN_S2_EX_CU')"

C1        
----------
china     
China     
J2        
j2        
j6        
J6        

  6 record(s) selected.

Db2 和 MySQL 关于 collation 的比较

总结来说:

  • Db2 的 UTF-8 identity 和 GBK identity 分别等价于 MySQL 的 utf8mb4_bin 和 gbk_bin
  • Db2 非 Unicode 的 system 映射到 language-aware 的 collation 无法在 MySQL 中找到等价的 collation
  • Db2 Unicode 的 UCA 中的 KUNIHAN_S1_EX 或 KUNIHAN_S2_EX 等价于 MySQL 的 utf8mb4_unicode_ci,但需要注意这里忽略大小写,所以不同大小写的相同字符串会按照输入顺序来排序输出。
  • MySQL 的 gb18030_chinese_ci 或 gbk_chinese_ci 在算法上也是 UCA 的多级比较(优先看整个字符串,再考虑大小写),所以 Db2 Unicode 的 UCA 中的 KGB2312HAN_S1_EX 或 KGB2312HAN_S2_EX 等价于 MySQL 的 gb18030_chinese_ci 或 gbk_chinese_ci,但需要注意这里忽略大小写,所以不同大小写的相同字符串会按照输入顺序来排序输出。
  • Db2 UCA 中的 CLDR2701_LZH_KGB2312HAN 和 CLDR2701_LZH 经测试可以根据拼音排序中文字符
  • Db2 UCA 中的 CLDR2701_LZH_KSTROKE 经测试可以根据笔画多少排序

附录

  1. Supported territory codes and code pages
  2. Code page 1386, Generic (SYSTEM_1386)
  3. Code set and collation combinations
  4. Unicode Collation Algorithm based collations
  5. UNICODE COLLATION ALGORITHM
  6. Unicode 字符串排序规则(二):如何比较字符串
  7. Unicode 归类算法 (UCA)
  8. 10.10.1 Unicode Character Sets
  9. CREATE DATABASE command
    10.Choosing a collation for a Unicode database
  • 10
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朱峥嵘(朱髯)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值