-
关于数据丢失的可能性:
-
NVARCHAR 字段都是 Unicode,这是一个单一的字符集,因此这些字段不会有任何数据丢失(这也包括同样存储为 UTF-16 Little Endian 的 XML 字段)。存储对象/列/索引/等名称的元数据字段都是NVARCHAR,所以不用担心这些。
-
VARCHAR 具有不同排序规则但不同排序规则之间的代码页相同的字段不会成为问题,因为代码页是字符集。
-
VARCHAR 具有不同排序规则并移动到不同代码页的字段(更改排序规则时)可能如果正在使用的任何字符未在新代码页中表示,则会丢失数据。但是,这只是在物理更改特定字段的排序规则(如下所述)时出现的问题,并且不会在更改数据库的默认排序规则时发生。
局部变量和字符串文字从数据库默认值中获取它们的排序规则。更改数据库默认值将更改用于局部变量和字符串文字的排序规则。但是更改数据库的默认排序规则不会更改用于该数据库表中现有字符串列的排序规则。在将列与文字和/或变量进行比较或连接时,这通常不会导致任何问题,因为由于排序优先级,文字和变量将采用列的排序规则。唯一的潜在问题是代码页转换可能发生在列排序规则使用的代码页中不可用的值介于 128 到 255 之间的字符。
-
如果您期望谓词/比较/排序/连接/等在更改数据库的默认排序规则时表现不同,那么您需要使用以下命令显式更改该列的排序规则:
ALTER TABLE [{table_name}]
ALTER COLUMN [{column_name}]
{same_datatype}
{same_NULL_or_NOT NULL_setting}
COLLATE {name_of_Database_default_Collation};
请务必指定当前正在使用的完全相同数据类型和NULL / NOT NULL 设置,否则如果它们不是默认值,它们可以恢复为默认值。之后,如果任何字符串列上的任何索引刚刚更改了其排序规则,那么您需要重建这些索引。
更改数据库的默认排序规则将更改某些特定于数据库的元数据的排序规则,例如sys.objects、sys.columns、sys.indexes 等中的name 字段。过滤这些系统针对局部变量或字符串文字的视图不会成为问题,因为 Collation 将在双方发生变化。但是,如果您将任何本地系统视图加入到字符串字段上的临时表中,并且本地数据库和tempdb 之间的数据库级排序规则不匹配,那么您将收到“排序规则不匹配”错误。这将在下面与补救措施一起讨论。
-
这两个排序规则之间的一个区别在于它们如何对VARCHAR 数据的某些字符进行排序(这不会影响NVARCHAR 数据)。非 EBCDIC SQL_ 排序规则对 VARCHAR 数据使用所谓的“字符串排序”,而所有其他排序规则,甚至是非 EBCDIC SQL_ 排序规则的 NVARCHAR 数据,使用所谓的“字排序” ”。不同之处在于,在“单词排序”中,破折号- 和撇号'(可能还有一些其他字符?)的权重非常低,除非字符串没有其他差异,否则基本上会被忽略。要查看此行为的实际效果,请运行以下命令:
DECLARE @Test TABLE (Col1 VARCHAR(10) NOT NULL);
INSERT INTO @Test VALUES ('aa');
INSERT INTO @Test VALUES ('ac');
INSERT INTO @Test VALUES ('ah');
INSERT INTO @Test VALUES ('am');
INSERT INTO @Test VALUES ('aka');
INSERT INTO @Test VALUES ('akc');
INSERT INTO @Test VALUES ('ar');
INSERT INTO @Test VALUES ('a-f');
INSERT INTO @Test VALUES ('a_e');
INSERT INTO @Test VALUES ('a''kb');
SELECT * FROM @Test ORDER BY [Col1] COLLATE SQL_Latin1_General_CP1_CI_AS;
-- "String Sort" puts all punctuation ahead of letters
SELECT * FROM @Test ORDER BY [Col1] COLLATE Latin1_General_100_CI_AS;
-- "Word Sort" mostly ignores dash and apostrophe
返回:
String Sort
-----------
a'kb
a-f
a_e
aa
ac
ah
aka
akc
am
ar
和:
Word Sort
---------
a_e
aa
ac
a-f
ah
aka
a'kb
akc
am
ar
虽然您将“丢失”“字符串排序”行为,但我不确定我是否会将其称为“功能”。这是一种被认为不受欢迎的行为(事实证明,它没有被带到任何 Windows 排序规则中)。但是,这 是两种排序规则之间行为的明显差异(同样,仅适用于非 EBCDIC VARCHAR 数据),并且您可能有基于“字符串排序”的代码和/或客户期望“ 行为。 这需要测试您的代码,并且可能需要研究这种行为变化是否会对用户产生负面影响。
-
SQL_Latin1_General_CP1_CI_AS 和Latin1_General_100_CI_AS 之间的另一个区别是能够对VARCHAR 数据执行Expansions(NVARCHAR 数据已经可以对大多数SQL_ 排序规则执行这些操作),例如将æ 处理为如果是ae:
IF ('æ' COLLATE SQL_Latin1_General_CP1_CI_AS =
'ae' COLLATE SQL_Latin1_General_CP1_CI_AS)
BEGIN
PRINT 'SQL_Latin1_General_CP1_CI_AS';
END;
IF ('æ' COLLATE Latin1_General_100_CI_AS =
'ae' COLLATE Latin1_General_100_CI_AS)
BEGIN
PRINT 'Latin1_General_100_CI_AS';
END;
返回:
Latin1_General_100_CI_AS
您在这里“失去”的唯一一件事是不能够进行这些扩展。一般来说,这是迁移到 Windows 排序规则的另一个好处。但是,就像从“字符串排序”到“单词排序”的移动一样,同样需要注意:这两个排序规则之间的行为存在明显差异(同样,仅针对 VARCHAR 数据),您可能有代码和/或基于没有这些映射的客户期望。 这需要测试您的代码,并且可能需要研究这种行为变化是否会对用户产生负面影响。
(首先在@Zarepheth 的answer 中注明,并在此处进行了扩展)
另一个区别(这也是迁移到 Windows 排序规则的一个好处)是过滤在 NVARCHAR 文字/变量/列上索引的 VARCHAR 列,您将不再使VARCHAR 专栏。这是由于 Windows 排序规则对 VARCHAR 和 NVARCHAR 数据使用相同的 Unicode 排序和比较规则。因为这两种类型之间的排序顺序相同,所以当VARCHAR 数据转换为NVARCHAR 时(显式或隐式由于数据类型优先级),索引中的项目顺序仍然有效。有关此行为的更多详细信息,请参阅我的帖子:Impact on Indexes When Mixing VARCHAR and NVARCHAR Types。
-
服务器级Collation用于设置系统数据库的Collation,包括[model]。 [model] 数据库用作创建新数据库的模板,其中包括每次服务器启动时的[tempdb]。因此,如果数据库的默认排序规则与实例的默认排序规则不匹配并且您将本地表连接到字符串字段上的临时表,那么您将收到 Collation-mismatch 错误。幸运的是,有一种简单的方法可以更正执行CREATE #TempTable 时“当前”的数据库与[tempdb] 之间的排序规则差异。创建临时表时,使用 COLLATE 子句声明排序规则(在字符串列上)并使用特定排序规则(如果您知道数据库将始终使用该排序规则)或 DATABASE_DEFAULT(如果您不始终知道将执行此代码的数据库的排序规则):
CREATE TABLE #Temp (Col1 NVARCHAR(40) COLLATE DATABASE_DEFAULT);
这对于表变量不是必需的,因为它们从“当前”数据库中获取默认排序规则。但是,如果您同时拥有表变量和临时表并将它们连接到字符串字段,那么您将需要使用COLLATE {specific_collation} 或COLLATE DATABASE_DEFAULT,如上所示。
服务器级排序规则还控制局部变量名称、CURSOR 变量名称和 GOTO 标签。虽然这些都不会受到本问题中处理的具体变化的影响,但至少需要注意。
-
如果有多个版本可用,最好使用所需排序规则的最新版本。从 SQL Server 2005 开始,引入了“90”系列排序规则,SQL Server 2008 引入了“100”系列排序规则。您可以使用以下查询找到这些排序规则:
SELECT * FROM sys.fn_helpcollations() WHERE [name] LIKE N'%[_]90[_]%'; -- 476
SELECT * FROM sys.fn_helpcollations() WHERE [name] LIKE N'%[_]100[_]%'; -- 2686
另外,虽然问题询问不区分大小写的排序规则,但应注意,如果其他人希望进行类似的更改但使用区分大小写的排序规则,那么 SQL Server 排序规则和 Windows 之间的另一个区别排序规则,仅用于 VARCHAR 数据,是先排序。意思是,如果您同时拥有A 和a,则SQL_ 排序规则将A 排序在a 之前,而非SQL_ 排序规则(以及SQL_ 排序规则在处理NVARCHAR 时) data) 将在A 之前排序a。