在我们的应用中,可能会遇到这样的情况:
在进行数据检索时,需要进行整形的处理(中间空格的处理不在此次讨论范围内,REPLACE函数即可处理),
1. 大、小写不敏感;
2. 全角、半角不敏感。
以生徒检索为例,假设需要根据生徒的氏名去数据库中检索匹配的生徒。并且假设数据库中存在一个全角半角、大小写混杂的生徒名为“ ”,要求氏名检索时需要进行整形的处理。但是,SQL Server中并没有现成的函数可以进行全角/半角的转换,那么如何处理呢?有一个方法是不在SQL Server中根据氏名作为条件进行匹配。而是首先将生徒检索出后,在BR层做整形处理进行氏名的匹配。显然,这不是一个好的解决办法,效率上就存在着极大的问题。
有没有办法利用SQL Server中处理这个问题呢?答案是肯定的。解决办法就是运用SQL Server的排序规则来处理。
SQL Server的排序规则由这样几部分组成:代码页、区分大小写、区分重音、区分宽度。
最后一个在SQL Server的联机帮助中没有进一步提及,其实本篇遇到的问题就是由于这个原因造成的。
区分宽度:指定 SQL Server 区分相同字符的单字节表示法(半角)和双字节表示法(全角)。
请参阅下文Michael Kaplan所做的详细解说,希望对你有帮助。Thanks!
排序规则
每个人都把排序的数据当作理所当然的东西;毕竟,有什么比字母表更基本呢? 我们当中的一些人可能会想到使用不同字母集的语言,如希腊语、俄语、泰语或日语。但至少在美国,每个人似乎都认为他们唯一需要考虑的就是字母表。
问题是他们都错了! 无论您是否想了解懂西班牙语的用户为什么希望将字母组合“ch”放在字母“h”之后作为单个字符进行排序,您都必须知道非英语语言具有不同的排序规则。通常,最有效的疏远应用程序最终用户的方法之一就是把基本排序这样的任务弄错。
要解决问题,可以利用排序规则(或排序顺序)和称作字符串标准化的技术。这里的“标准化”不同于数据库开发人员过去所习惯的标准化概念,因为它不是一个设计问题;当您提到字符串标准化时,实际是在考虑如何比较两个字符串使它们可以排序。这可以通过创建索引来进行优化。
对于非 Unicode 列,排序规则具有另一种非常重要的含义:排序规则指定了数据的代码页,因而指定了可以显示哪些字符。数据可以在各 Unicode 列间毫无阻碍地移动,但数据却无法在非 Unicode 列中进行移动。
SQL Server 6.5 和早期版本中的排序规则
在 SQL Server 6.5 和早期版本中,通常还依赖排序规则来指定用于语言的代码页。这些版本中存在与不同排序顺序(例如在各种拉丁语中)相关的限制。另外,如果您使用的是 Latin-1,则只能支持西欧语言。因此,在 SQL Server 单个例程上的信息中可显示的不同区域设置数(即特定区域中使用的不同语言的数目)受到了限制。这种基本问题同样适用于 SQL Server 后期版本中非 Unicode 字段的排序规则。此外,具有“最适合的”代码页的语言(例如前面在非 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 中,排序规则还用于处理非 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 排序规则属于例外。此规则同样适用于其他所有排序规则;只是不同排序规则具有不同的例外。
在多个级别指定的排序规则
在 SQL Server 2000 中,可以在以下级别指定排序规则:
§ 服务器级别
§ 数据库级别
§ 列级别
§ 表达式中
在服务器级别指定的排序规则
服务器级别是排序规则通常所处的级别,它在多数情况下是唯一需要设置的排序规则。如果您没有明确设置数据库级别的排序规则,当创建该排序规则后,它将作为服务器上所有数据库中所有排序规则的默认值。因为始终要为一个数据库提供一个排序规则,所以除非是在创建数据库时,否则决不会真正考虑服务器级别的排序规则。
您可以更改该排序规则,而无需使用“重建 Master”实用程序 (RebuildM.exe) 来重新运行 Setup。该实用程序位于 Program Files/Microsoft SQL Server/80/Tools/BINN 目录。有关详细信息,请参见 SQL Server Books Online for SQL Server 2000 中的 "Rebuild master Utility"(重建 master 实用程序)主题。
您还可以使用 Transact-SQL SERVERPROPERTY 函数在服务器上查询排序规则,例如:
SELECT CONVERT(char, SERVERPROPERTY('collation'))
每个数据库都可以有一种唯一的排序规则,而排序顺序则在数据库级别设置。下面的图解(图 6)说明了使用 SQL Server 企业管理器来设置排序规则的方法。
图 6:使用企业管理器设置排序规则
您还可以使用 Transact-SQL 来设置排序规则顺序。例如,要按照捷克共和国的排序顺序和区分大小写及重音的形式创建一个新的数据库,可以使用如下语句:
USE master
GO
CREATE DATABASE Products
ON
( NAME = products_dat,
FILENAME = 'c:/program files/microsoft sql server/mssql/data/products.mdf' )
COLLATE Czech_CS_AS
GO
有趣的是,您甚至可以使用 ALTER DATABASE 语句来更改现有数据库的排序规则(当使用 SQL Server 企业管理器时,该语句不可用)。例如,以下语句将 Products 数据库的排序规则从 Czech_CS_AS 更改为 Czech_CI_AI (将区分大小写和重音更改为不区分大小写和重音):
ALTER DATABASE Products
COLLATE Czech_CI_AI
更改数据库排序规则之前的注意事项
要更改数据库的排序规则,必须符合以下所有条件:
§ 不会有其他人正在使用该数据库。
§ 没有依赖于数据库排序规则的架构绑定对象。符合条件的架构绑定对象包括以下任何内容:
· 用户定义的函数和用 SCHEMABINDING 创建的视图
· 已计算的列
· CHECK 约束
· 表值函数,它们使用从默认数据库排序规则继承的排序规则来返回包含字符列的表。
§ 尝试更改数据库排序规则的行为不会导致任何系统名称的重复。这是很容易想象的,例如尝试将排序规则从 French_CI_AS 更改为 French_CS_AS(或将不区分大小写更改为区分大小写)。对于 SQL Server 早期版本中的排序规则,可能有两个分别名为 Table1 和 TABLE1 的表;然而,对于 SQL Server 2000 的排序规则,这种情形会导致重复。可能导致这种重复的对象包括:
· 对象名(如过程、表、触发器或视图)。
· 构架名(如组、角色或用户)。
· 标量类型名(如系统和用户定义的类型)。
· 全文目录名
· 对象中的列名或参数名。
· 表中的索引名。
以上限制都具有实际的意义,它们将防止您执行会破坏数据或数据库的操作。实际上,有些人甚至认为这些规则不够严格! 如果 text、varchar 或 char 字段中包含数据并且列上没有显式的排序规则,那么更改数据库排序规则就会改变数据编码的解释方式,从而毁坏 ASCII 范围(包含在所有代码页中)外的所有字符。这样做是很危险的。相反,如果数据库包含的文本数据列不属于 Unicode 类型并且这些列没有它们自己的显式排序规则集(参见下面的在列级别指定的排序规则),您就应该尽量避免更改任何这些数据库的排序规则。
此外,您也可以使用 Transact-SQL DATABASEPROPERTYEX 函数来查找数据库的排序规则,例如:
SELECT CONVERT(char, DATABASEPROPERTYEX('pubs', 'collation'))
在 SQL Server 2000 中,您可以更改特定列中文本的排序规则。这是很有用的,例如在需要对密码列强制区分大小写这种情况下。在其他情形下,可能会用到不同的语言列。例如,客户名可能需要以使用 Latin1_General 的 Unicode 来进行范围最广的适当排序,而产品名则可能会始终采用的是希腊语,在这种情形下,希腊语排序规则可能比较恰当。以下图解(图 7)显示了在使用 SQL Server 企业管理器进行表设计的过程中的排序规则说明。
图 7:使用企业管理器进行表设计时的排序规则的详细说明
当您单击“...”按钮时,将出现以下图解中所示的对话框。在该对话框(图 8)中,您可以选择一种排序规则。
图 8:“排序规则”对话框
您还可以使用 Transact-SQL 设置来列级别的排序规则。在 CREATE TABLE 语句中,将 COLLATE 子句添加到列定义中即可。以下示例中的作业说明有一个用于阿拉伯语的排序规则集(不区分大小写、重音和假名类型)。
CREATE TABLE jobs
(
job_id smallint
IDENTITY(1,1)
PRIMARY KEY CLUSTERED,
job_desc varchar(50)
COLLATE Arabic_CI_AI_KS
NOT NULL
DEFAULT 'New Position - title not formalized yet',
)
您可以使用 ALTER TABLE 语句来更改具有新数据类型的列级别排序规则(ntext 或 text 列除外)。但是,您可以使用 SQL Server 企业管理器更改 ntext 列的排序规则。这是因为 SQL Server 企业管理器会创建一个 temp 表,将数据移动到新的 temp 表,删除旧表,使用新的排序规则创建一个新表,然后再将数据复制回新表。
当您需要向不同国家的用户显示数据并希望按适当的区域设置进行排序时,可能会遇到许多情况。对于 SQL Server 2000,您可以在表达式中指定排序规则。这种强大的新功能允许您以特定的方式进行排序,这样 ORDER BY 子句就可针对于具体的语言。
例如,以下查询按照名和姓对 Customers 表进行排序(使用立陶宛语排序顺序是排序规则差异的一个很好示例,因为字母 Y 在字母后排序的规则相当明显,很容易注意)。
SELECT
*
FROM
tblCustomers
ORDER BY
LastName COLLATE Lithuanian_AI_CI,
FirstName COLLATE Lithuanian_AI_CI
您还可以参见 SQL Server Books Online for SQL Server 2000 中有关常规比较的示例,如:
SELECT
*
FROM
Table1
WHERE
Field1 = Field2 COLLATE Turkish_ci_ai
假定 Table1 没有显式的列级排序规则,那么这两列都将按土耳其语排序顺进行比较。要详细了解为什么会出现这种情况,请参见本文稍后的排序规则的优先规则。
COLLATE 关键字
使用 COLLATE 关键字的语法是:
COLLATE [<Windows_Collation_name>|<SQL_Collation_Name]
很难对排序规则的名称作出选择。关键字可以在数据库级别、列级别或在表达式中指定。通常,只要字段不是 Unicode 类型(ntext、nvarchar 或 nchar),就会使用先前将排序规则转换为代码页的步骤。
有两种类型的排序规则:
Windows 排序规则
这些规则是由 Windows 定义的。您完全有权指定是否区分大小写、重音、假名和宽度以及定义二进制排序。
SQL 排序规则
这些排序规则是由 SQL Server 为解决遗留问题而定义的。您不具有配置这些排序规则的充分权限。
一般来说,您应该尽可能地使用 Windows 排序规则。以下图解(图 9)显示了一个排序规则可能会如何变化的简单示例。在该示例中使用的是 pubs 数据库。Y 是否出现在 I 和 J 之间或 X 和 Z 之间,取决于是否使用立陶宛语排序规则,这无疑会影响查询中各项的排序方式。
图 9:排序规则对排序影响的示例
在 SQL Server 2000 中,您可以在服务器、数据库和列级别以及在表达式中指定排序规则。这些排序规则是如何相互影响的?
这种相互影响需要遵循某些直接的规则,虽然这些规则看起来可能有些费解,但确实是必需的。下面显示了 A 和 B 作为要比较的两个不同部分的相互影响。
| 显式 B | 隐式 B | 默认值 | 无排序规则 |
显式 A | 运行时错误 | 显式 A | 显式 A | 显式 A |
隐式 A | 隐式 B | 无排序规则 | 隐式 A | 无排序规则 |
默认值 | 隐式 B | 隐式 B | 默认值 | 无排序规则 |
无排序规则 | 隐式 B | 无排序规则 | 无排序规则 | 无排序规则 |
下面提供了该表中各项的定义。
显式 A/显式 B
为给定表达式显式定义的排序规则。
隐式 A/隐式 B
已经在列级别定义的排序规则。
默认值
正在使用的数据库级别排序规则。
无排序规则
两个操作符之间存在冲突;处理表达式时无排序规则。
正象您看到的那样,SQL Server 无法处理表达式的仅有情况包括:当您显式定义两个不同且相互冲突的排序规则时,或当您设法比较两项却无法找到进行比较的任何共同点时。它们实际上并不是限制,而是可以理解的规则。SQL Server 只需要您提供一些比较的依据。
例如,在创建表时考虑使用下面的 Transact-SQL 语句:
CREATE TABLE TestTab (
id int,
GreekCol nvarchar(10) COLLATE greek_ci_as,
LatinCol nvarchar(10) COLLATE latin1_general_cs_as
)
INSERT TestTab VALUES (1, N'A', N'a')
GO
该语句创建了一个包含以下两列的表:一列使用不区分大小写和区分重音的希腊语排序规则,而另一列使用区分大小写和重音的通用 Latin1 排序规则。
您可以尝试使用查询来显式比较这两列:
SELECT *
FROM TestTab
WHERE GreekCol = LatinCol
但是,该查询会返回一个错误:
Msg 446, Level 16, State 9, Server V-MICHKA3, Line 1
无法解决等于运算的排序规则冲突。
之所以会出现此错误,是因为服务器无法使用不同的排序规则来比较两段文本。但是,如果您使用 COLLATE 关键字显式创建一个允许这两列兼容的表达式,则查询将以如下方式执行:
SELECT *
FROM TestTab
WHERE GreekCol = LatinCol COLLATE greek_ci_as
还需注意的是,尽管 LatinCol 通常有一个区分大小写的排序规则,但表达式不区分大小写的排序规则会将其覆盖,从而使“A”的大写和小写被视为等同。
COLLATE 关键字的限制
COLLATE 关键字及其相关功能是令人难以置信的。本文作者相信,在同时代的企业数据库产品中,它们也是无以伦比的。不过,它们仍存在以下列出的一些限制。请注意,这些限制都有解决办法。此处所述的限制有助于了解您可以直接执行哪些任务以及哪些任务需要一点额外的工作。
返回不完整的排序规则列表
fn_helpcollations 函数(请参见上文在列级别指定的排序规则中的图解)返回了完整的排序规则列表。但是,按照上文数据库级别的排序规则中所述对话框的内容,SQL Server 完全可以列出一个区域设置(如阿尔巴尼亚语),并将标记的其余部分提供为选项,以最终返回完整的字符串。如果要为该功能提供一个用户界面,则必须执行一点额外的操作。
在列级别定义排序规则的问题
您每隔多久会遇到一个需要一种排序顺序(如 Latin1_General)的数据库和一个需要另一种排序顺序(如希腊语)的列?有时,这可能是一个相当关键的问题,但是在其他时候,如果数据库中的数据未使用单一的排序规则,那么该数据就可能是需要按多种排序规则进行排序的多种语言数据。由于可以定义多种排序规则并且每种排序规则都可以编制索引,所以您可以通过指定希腊语排序规则来访问希腊语数据,还可以使该查询成为索引搜索。
最后一个子句“使该查询成为索引搜索”是问题的关键。在以前提供的示例中,使用查询 ORDER BY 子句中的 COLLATE 表达式就可实现这种功能;但是,这并不是索引排序,因此对大型数据集而言,这种排序较慢。事实上,只有当列中没有单语言数据或数据库已取消标准化以便在不同列中存储不同语言时,列级排序规则才有意义。
LCID 和排序规则
Windows 使用区域设置 ID (LCID) 来定义排序。如果您正在对结果进行格式化,那么您可能已经有了现成的 LCID(或者,您可以通过指定 1024 或使用 Microsoft Visual Basic® 格式化函数来使用默认的 LCID,以完成您的工作)。事实上,如果您是在基于 Web 的 ASP 应用程序中进行这项工作,则可以使用 Microsoft Visual Basic Scripting Edition (VBScript) 中的 SetLocale 函数来更改要使用日期/时间、数字格式以及任何区域设置的货币格式首选项。不过,排序规则和 LCID 之间无法相互映射:由于 LCID 到排序规则是多对一的映射,您可以从一种排序规则中获得一个 LCID,但却无法从一个 LCID 中获得一种排序规则。
这样为什么不方便呢?好吧,设想您有一个多种语言网站,来自不同国家和地区的人们都可以访问该网站并查看产品信息。您可能已经将他们浏览器的 HTTP_ACCEPT_LANGUAGE 变量映射为 LCID,以使用 Session.LCID 属性对日期和货币值进行格式化,而且为了便于使用,您认为使用他们的区域设置进行排序是明智的选择。
要构建自己的映射函数来解决这个问题,请参见 SQL Server Books Online for SQL Server 2000 中的 "Rebuild master Utility"(Windows 排序规则指示器)主题中的转换表。
ISO 字符串和排序规则
您可以使用如下脚本来获取 VBScript 中的 HTTP_ACCEPT_LANGUAGE 变量:
Dim stLang
stLang = Request.ServerVariables("HTTP_ACCEPT_LANGUAGE")
鉴于该值是许多 Web 开发人员在处理区域设置信息所拥有的唯一值,所以 VBScript SetLocale 函数不仅包含 LCID 值,而且直接接受该值。这意味着您不必执行将该值映射为 LCID 的中间步骤。由于 SQL Server2000 无法接受象“en-us”(美国英语)这样的字符串并将其正确映射到 Latin1_General 排序规则,也无法接受象“vi”(越南语)这样的字符串并将其正确映射到越南语排序规则,因此您必须自己映射所有的字符串。
如何定义自定义排序规则?
看过无数排序规则选项后,许多开发人员通常会提出如何定义他们自己的排序规则这一问题。答案是他们不能定义自定义排序规则。如果排序规则不能添加到 Windows 2000 中,则同样不能添加到 SQL Server 2000 中。这是因为排序规则主要用于定义对 Unicode 标准中每个已定义字符进行排序的方法,而并没有设计任何用户界面来让用户创建排序规则。