排序规则
每个人都把排序的数据当作理所当然的东西;毕竟,有什么比字母表更基本呢? 我们当中的一些人可能会想到使用不同字母集的语言,如希腊语、俄语、泰语或日语。但至少在美国,每个人似乎都认为他们唯一需要考虑的就是字母表。
问题是他们都错了! 无论您是否想了解懂西班牙语的用户为什么希望将字母组合“ch”放在字母“h”之后作为单个字符进行排序,您都必须知道非英语语言具有不同的排序规则。通常,最有效的疏远应用程序最终用户的方法之一就是把基本排序这样的任务弄错。
要解决问题,可以利用排序规则(或排序顺序)和称作字符串标准化的技术。这里的“标准化”不同于数据库开发人员过去所习惯的标准化概念,因为它不是一个设计问题;当您提到字符串标准化时,实际是在考虑如何比较两个字符串使它们可以排序。这可以通过创建索引来进行优化。
对于非 Unicode 列,排序规则具有另一种非常重要的含义:排序规则指定了数据的代码页,因而指定了可以显示哪些字符。数据可以在各 Unicode 列间毫无阻碍地移动,但数据却无法在非 Unicode 列中进行移动。
SQL Server 6.5 和早期版本中的排序规则
在 SQL Server 6.5 和早期版本中,通常还依赖排序规则来指定用于语言的代码页。这些版本中存在与不同排序顺序(例如在各种拉丁语中)相关的限制。另外,如果您使用的是 Latin-1,则只能支持西欧语言。因此,在 SQL Server 单个例程上的信息中可显示的不同区域设置数(即特定区域中使用的不同语言的数目)受到了限制。这种基本问题同样适用于 SQL Server 后期版本中非 Unicode 字段的排序规则。此外,具有“最适合的”代码页的语言(例如前面在sqlserver2000.asp#intlfeaturesinsqlserver2000_non-unicodetext">非 Unicode 文本类型:char、varchar 和 text 中提及的波斯语)方面的问题在这里也适用。
SQL Server 7.0 中的排序规则
在每台服务器上,SQL Server 7.0 都有一个 Unicode 排序规则和一个非 Unicode 排序规则。由于每个代码页可以支持多种排序,所以非 Unicode 排序规则是由代码页和排序顺序 ID 两方面的决策组成的。例如,拉丁语言通常会既允许区分大小写的排序也允许不区分大小写的排序,而简体中文既允许按笔画排序也允许按拼音排序。
在 Unicode 排序规则中,可以在列中包含任何语言的任何字符,所以在这里提供了各种可用的排序规则来确保任何特定于排序规则的差异都得到正确的处理。这是解决“最适合的”代码页问题的正确方法,因为如果使用一般的 Unicode 排序规则对波斯语数据进行排序,就可以为用户提供他们所需的数据。Unicode 排序规则由一个区域设置和多个比较样式组成。区域设置通常按国家或文化区域来命名。它们根据该区域中的标准对字符进行排序。Unicode 排序规则还为采用 Unicode 标准的所有字符提供了一种排序顺序,但指定的区域设置将具有优先权。
下表列出了 SQL Server 7.0 中所支持的唯一 Unicode 排序规则。未列出的任何区域设置应该使用“通用 Unicode 排序规则”。
区域设置 ID (LCID) |
说明 |
1033 |
通用 Unicode |
33280 |
二进制顺序 |
1027 |
加泰罗尼亚语 |
197636 |
中文汉语拼音字母(中国台湾地区) |
2052 |
中文标点符号 |
133124 |
中文笔画 |
1028 |
中文笔画(中国台湾地区) |
1050 |
克罗地亚语 |
1029 |
捷克语 |
1043 |
荷兰语 |
1061 |
爱沙尼亚语 |
1036 |
法语 |
66615 |
现代格鲁吉亚语 |
1031 |
德语 |
66567 |
德语电话簿 |
1038 |
匈牙利语 |
66574 |
匈牙利技术 |
1039 |
冰岛语 |
1040 |
意大利语 |
1041 |
日语 |
66577 |
日语 Unicode |
1042 |
朝鲜语 |
66578 |
朝鲜语 Unicode |
1062 |
拉脱维亚语 |
1063 |
立陶宛语 |
1071 |
FYRO 马其顿语 |
1044 |
挪威语/丹麦语 |
1045 |
波兰语 |
1046 |
葡萄牙语 |
1048 |
罗马尼亚语 |
1051 |
斯络伐克语 |
1060 |
斯络文尼亚语 |
1034 |
传统西班牙语 |
3082 |
现代西班牙语 |
1053 |
瑞典语/芬兰语 |
1054 |
泰语 |
2057 |
英国英语 |
1058 |
乌克兰语 |
1066 |
越南语 |
从以上列表中您可以看到,并非所有语言都包括在内;但不要紧,因为没有必要将所有语言都包括在内。例如,通用 Unicode 排序顺序不仅可以正确地处理数据,还可以处理以下语言的排序:南非荷兰语、阿尔巴尼亚语、阿拉伯语、巴斯克语、白俄罗斯语、保加利亚语、英语、法罗语、波斯语、传统格鲁吉亚语、希腊语、希伯来语、印地语、印度尼西亚语、马来语、俄语、塞尔维亚语、斯瓦西里语和乌尔都语。但是,表中列出的其他语言与通用 Unicode 排序规则具有一个或多个不同之处。
应该强调的是,SQL Server 的开发人员并不是“政坛”人士,因而要求他们“使用另一国家/地区的排序顺序”绝不是想冒犯任何国家/地区。事实上,居住在南斯拉夫塞尔维亚地区的人可能不必为使用克罗地亚语排序顺序而担心,因为克罗地亚语和塞尔维亚语使用的是相同的排序规则,其名称具有随意性。当与其他国家/地区的客户协同工作时,只会使用数字,因为名称实际上只是随意的说明。最为重要的是,您可以选择一种将使您的数据得到正确处理的排序规则。
SQL Server 7.0 中有一项很重要的更改,这就是为字符串比较提供了与操作系统无关的模型,这样从 Windows 95 到 Windows 2000 的所有操作系统间的排序规则就可以保持一致。该代码以 Windows 2000 为实现其自身字符串标准化而使用的相同代码为基础,可以在所有计算机上封装成相同的代码。有了这一更改,SQL Server 不再依靠操作系统来实现其国际化功能 - 无论是最小的 MSDE 安装,还是最大的 SQL Server Enterprise Edition。
SQL Server 2000 的排序规则
在 SQL Server 2000 中,排序规则模型已经过更改,因为:
- 对两个不同排序规则的要求会导致误解。
- 需要更灵活的模型来处理可指定一个排序规则的所有新位置。
- 在 SQL Server 2000 中,排序规则还用于处理非 Unicode 列的代码页,因此会需要更多的排序规则。
SQL Server 2000 为处理 Unicode 和非 Unicode 排序而设计了一个一致的模型。该模型支持下表中所显示的语言。
SQL Server 2000 的排序规则 |
|
|
Albanian |
Arabic |
Chinese_PRC |
Chinese_PRC_Stroke |
Chinese_Taiwan_Bopomofo |
Chinese_Taiwan_Stroke |
Cyrillic_General |
Croatian |
Czech |
Danish_Norwegian |
Estonian |
Finnish_Swedish |
French |
Georgian_Modern_sort |
German_PhoneBook |
Greek |
Hebrew |
Hindi |
Hungarian |
Hungarian_Technical |
Icelandic |
Japanese |
Japanese_Unicode |
Korean_Wansung |
Korean_Wansung_Unicode |
Latin1_General |
Latvian |
Latvian |
Lithuanian_Classic |
FYRO Macedonian |
Modern_Spanish |
Polish |
Romanian |
Slovak |
Slovenian |
Thai |
Traditional_Spanish |
Turkish |
Ukrainian |
Vietnamese |
|
|
以上每一种排序规则都带有一系列后缀,以便定义是否区分大小写、重音、宽度或假名。下表显示了可能存在的确切后缀。上表列出的 40 种语言中每一种都支持下表中的 17 种后缀,共计 680 种的 Windows 排序规则。
排序规则的后缀 |
含义 |
_BIN |
二进制排序 |
_CI_AI |
不区分大小写、不区分重音、不区分假名类型、不区分宽度 |
_CI_AI_WS |
不区分大小写、不区分重音、不区分假名类型、区分宽度 |
_CI_AI_KS |
不区分大小写、不区分重音、区分假名类型、不区分宽度 |
_CI_AI_KS_WS |
不区分大小写、不区分重音、区分假名类型、区分宽度 |
_CI_AS |
不区分大小写、区分重音、不区分假名类型、不区分宽度 |
_CI_AS_WS |
不区分大小写、区分重音、 不区分假名类型、区分宽度 |
_CI_AS_KS |
不区分大小写、区分重音、区分假名类型、不区分宽度 |
_CI_AS_KS_WS |
不区分大小写、区分重音、区分假名类型、区分宽度 |
_CS_AI |
区分大小写、不区分重音、 不区分假名类型、不区分宽度 |
_CS_AI_WS |
区分大小写、不区分重音、不区分假名类型、区分宽度 |
_CS_AI_KS |
区分大小写、不区分重音、区分假名类型、不区分宽度 |
_CS_AI_KS_WS |
区分大小写、不区分重音、区分假名类型、区分宽度 |
_CS_AS |
区分大小写、区分重音、不区分假名类型、不区分宽度 |
_CS_AS_WS |
区分大小写、区分重音、不区分假名类型、区分宽度 |
_CS_AS_KS |
区分大小写、区分重音、区分假名类型、不区分宽度 |
_CS_AS_KS_WS |
区分大小写、区分重音、区分假名类型、区分宽度 |
这些语言的名称是随意的。选择这些名称是为了正确地表示非 Unicode 数据的每一个唯一受支持的代码页,并表示所有数据的排序顺序。在许多情况下(某种语言可以在另一代码页上完全显示,或者某种语言所需的排序顺序可以被其他排序顺序替换),该语言会因其可以被充分替换而从该列表中“删除”。请注意,是否区分假名和宽度的默认设置是不区分假名和宽度。
为了确保 SQL Server 早期版本的代码页得到正确的支持,SQL Server 2000 中还包括了许多向下兼容并特定于 SQL 的排序顺序。下面列出了这些特定于 SQL 的排序顺序。许多排序顺序都支持上述的部分后缀,但不支持所有后缀。
特定于 SQL 的排序顺序 |
|
|
SQL_1xCompat_CP850 |
SQL_Estonian_CP1257 |
SQL_Latin1_General_Pref_CP437 |
SQL_AltDiction_CP1253 |
SQL_Hungarian_CP1250 |
SQL_Latin1_General_Pref_CP850 |
SQL_AltDiction_CP850 |
SQL_Icelandic_Pref_CP1 |
SQL_Latvian_CP1257 |
SQL_AltDiction_Pref_CP850 |
SQL_Latin1_General_CP1 |
SQL_Lithuanian_CP1257 |
SQL_Croatian_CP1250 |
SQL_Latin1_General_CP1250 |
SQL_MixDiction_CP1253 |
SQL_Czech_CP1250 |
SQL_Latin1_General_CP1251 |
SQL_Polish_CP1250 |
SQL_Danish_Pref_CP1 |
SQL_Latin1_General_CP1253 |
SQL_Romanian_CP1250 |
SQL_EBCDIC037_CP1 |
SQL_Latin1_General_CP1254 |
SQL_Scandinavian_CP850 |
SQL_EBCDIC273_CP1 |
SQL_Latin1_General_CP1255 |
SQL_Scandinavian_Pref_CP850 |
SQL_EBCDIC277_CP1 |
SQL_Latin1_General_CP1256 |
SQL_Slovak_CP1250 |
SQL_EBCDIC278_CP1 |
SQL_Latin1_General_CP1257 |
SQL_Slovenian_CP1250 |
SQL_EBCDIC280_CP1 |
SQL_Latin1_General_CP437 |
SQL_SwedishPhone_Pref_CP1 |
SQL_EBCDIC284_CP1 |
SQL_Latin1_General_CP850 |
SQL_SwedishStd_Pref_CP1 |
SQL_EBCDIC285_CP1 |
SQL_Latin1_General_Pref_CP1 |
SQL_Ukrainian_CP1251 |
SQL_AltDiction_CP1253 |
SQL_Hungarian_CP1250 |
|
SQL_Latin1_General_Pref_CP850 |
|
|
您可以通过使用 COLLATIONPROPERTY 函数来检索有关排序规则的实际信息。除以前使用的 CodePage 值之外,您还可以传递其他信息类型,例如 LCID,它返回 Windows 区域设置 ID(对于 SQL 排序规则将返回 Null)。您还可以指定 Windows ComparisonStyle (对于“二进制”和 SQL 排序规则均返回 Null)。此信息可用于验证对于所有的 Windows 排序规则,Windows 2000 和 SQL Server 中的字符串标准化是否真正等价。
例如,通过使用 fn_helpcollations() 函数可返回所有可用的排序规则:
SELECT * FROM ::fn_helpcollations()
该查询在 SQL Server 2000 中返回了 753 行。不能添加额外的排序规则,除非要将其添加到服务包或将来的版本中。
排序规则如何指定数据的排序
务必要简要地说明排序规则实际上如何处理 Unicode 数据。SQL Server 中 Unicode 列上的每种已定义排序规则都将对所有已定义的 Unicode 字符进行排序,这是无一例外的常规。由于数据排序方法存在很多差异,因此有多种不同的排序规则。现代格鲁吉亚语排序就是一个很好的示例。虽然格鲁吉亚语文本的传统排序按特定的顺序放置所有字符,但根据现代人的使用习惯,通常将某些很少使用的字符放在末尾。这些字符包括:
- HE,显示为:
- HEI,显示为:
- WE,显示为:
- HAR,显示为:
因此,可以使用两种方法对格鲁吉亚语字母表进行排序,如图 4 和图 5 所示。
图 4:格鲁吉亚语字母表排序的传统方法
图 5:格鲁吉亚语字母表排序的现代方法
这种方法不会阻止其他任何 Unicode 数据以 Latin1_General 排序规则所提供的相同排序来进行排序。事实上,所有排序规则都按传统形式对格鲁吉亚语进行排序,只有 Georgian_Modern_Sort 排序规则属于例外。此规则同样适用于其他所有排序规则;只是不同排序规则具有不同的例外。