我们有一个遗留数据库,其中一些(较旧)列使用“SQL_Latin1_General_CP1_CI_AS”,最近的更改使用了“Latin1_General_CI_AS”。
这是一个痛苦,因为连接需要额外的COLLATE语句才能工作。
我想把所有内容都归结为“Latin1_General_CI_AS”。从我可以收集的内容来看,它们或多或少是相同的排序规则,在此过程中我不会丢失数据......
有人知道是不是这样吗?
答案 0 :(得分:30)
这是一个更完整的答案:
这些排序规则之间的主要区别在于它们如何应用字符扩展规则。某些拉丁字符可能会扩展为多个字符。在处理非Unicode文本时,SQL_xxxx排序规则可能会忽略这些字符扩展,但会将它们应用于unicode文本。因此:当使用一个校对与另一个校对时,连接,排序和比较可能会返回不同的结果。
示例:
在Latin1_General_CI_AS
下,这两个语句会返回相同的记录集,因为ß
会扩展为ss
。
SELECT * FROM MyTable3 WHERE Comments = 'strasse'
SELECT * FROM MyTable3 WHERE Comments = 'straße'
使用SQL_Latin1_General_CP1_CI_AS
时,上述语句会返回不同的记录,因为ß
被视为与ss
不同的字符。
答案 1 :(得分:20)
如果您要更改数据库的排序规则,那么您肯定应该了解一些内容,以便您可以相应地进行规划:
关于数据丢失的可能性:
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
设置,否则如果不是默认值,则可以恢复为默认值值。之后,如果任何字符串列上的任何索引刚刚更改了其排序规则,那么您需要重建这些索引。
更改数据库的默认排序规则将更改某些特定于数据库的元数据的排序规则,例如name
,sys.objects
中的sys.columns
字段,sys.indexes
等。根据局部变量或字符串文字过滤这些系统视图不会成为问题,因为整理将在双方都发生变化。但是,如果您将任何本地系统视图连接到字符串字段上的临时表,并且本地数据库与tempdb
之间的数据库级排序规则不匹配,那么您将获得"整理不匹配"错误。下面将讨论此问题以及补救措施。
这两个排序规则之间的一个区别在于它们如何为VARCHAR
数据排序某些字符(这不会影响NVARCHAR
数据)。非EBCDIC SQL_
Collations使用所谓的" String Sort"对于VARCHAR
数据,而非EBCDIC NVARCHAR
归类的所有其他归类,甚至SQL_
数据都使用所谓的" Word排序"。区别在于" Word排序",短划线-
和撇号'
(以及可能还有一些其他角色?)的重量非常轻,基本上被忽略,除非那里有在字符串中没有其他差异。要查看此行为,请运行以下命令:
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
数据),您可能会根据&而得到代码和/或客户期望#34;字符串排序"行为。 这需要测试您的代码并进行研究,以确定此行为的变化是否会对用户产生任何负面影响。
SQL_Latin1_General_CP1_CI_AS
和Latin1_General_100_CI_AS
之间的另一个区别是能够对VARCHAR
数据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
返回:
VARCHAR
你唯一的事情就是"失去"这里是不能够做这些扩展。一般来说,这是迁移到Windows排序规则的另一个好处。但是,就像使用" String Sort" to" Word Sort"移动,同样的谨慎适用:它是两个排序规则之间行为的明确差异(同样,仅适用于VARCHAR
数据),并且您可能基于而不是拥有这些映射。 这需要测试您的代码并可能进行研究,以确定此行为更改是否会对用户产生任何负面影响。
(首先在@ Zarepheth' s Expansions中注明并在此扩展)
另一个区别(移植到Windows排序规则的好处)是过滤NVARCHAR
文字/变量/列上的VARCHAR
列,您将不再无效VARCHAR
列上的索引。这是因为Windows Collations对NVARCHAR
和VARCHAR
数据使用相同的Unicode排序和比较规则。由于两种类型之间的排序顺序相同,因此当NVARCHAR
数据转换为[model]
(由于数据类型优先级而显式或隐式)时,索引中项目的顺序仍然有效。有关此行为的详细信息,请参阅我的帖子:answer。
服务器级排序规则用于设置系统数据库的排序规则,其中包括[model]
。 [tempdb]
数据库用作模板来创建新数据库,其中包括每个服务器启动时的CREATE #TempTable
。因此,如果数据库的默认排序规则与实例的默认排序规则和不匹配,则将本地表连接到字符串字段上的临时表,则会出现排序规则不匹配错误。幸运的是,有一种简单的方法可以纠正数据库之间的整理差异,即#34;当前"执行[tempdb]
时COLLATE
。创建临时表时,使用DATABASE_DEFAULT
子句声明排序规则(在字符串列上)并使用特定排序规则(如果您知道数据库将始终使用该排序规则),或CREATE TABLE #Temp (Col1 NVARCHAR(40) COLLATE DATABASE_DEFAULT);
(如果你不总是知道执行此代码的数据库的排序规则):
COLLATE {specific_collation}
这对于表变量不是必需的,因为它们从"当前"得到它们的默认排序规则。数据库。但是,如果您同时拥有表变量和临时表并将它们连接到字符串字段,则需要使用COLLATE DATABASE_DEFAULT
或CURSOR
,如上所示。
服务器级排序规则还控制局部变量名称,GOTO
变量名称和SELECT * FROM sys.fn_helpcollations() WHERE [name] LIKE N'%[_]90[_]%'; -- 476
SELECT * FROM sys.fn_helpcollations() WHERE [name] LIKE N'%[_]100[_]%'; -- 2686
标签。虽然这些问题中没有一个会受到本课题所涉及的具体变化的影响,但至少应该注意一些事项。
如果有多个版本,最好使用所需归类的最新版本。从SQL Server 2005开始," 90"引入了一系列排序规则,SQL Server 2008引入了一个" 100"整理系列。您可以使用以下查询找到这些排序规则:
VARCHAR
此外,虽然问题是关于不区分大小写的Collations,但应该注意的是,如果其他人希望进行类似的更改但使用区分大小写的Collations,那么SQL Server Collations和Windows之间的另一个区别归类,仅适用于A
数据,是哪种情况首先排序。这意味着,如果您同时拥有a
和SQL_
,则A
归类将在a
之前对SQL_
进行排序,而对非SQL_
归则进行排序(处理NVARCHAR
数据时a
归类)会在A
之前对{{1}}进行排序。
有关更改数据库整理或整个实例的更多信息和详细信息,请参阅我的帖子:
Impact on Indexes When Mixing VARCHAR and NVARCHAR Types
有关使用字符串和排序规则的详细信息,请访问:Changing the Collation of the Instance, the Databases, and All Columns in All User Databases: What Could Possibly Go Wrong?
答案 2 :(得分:14)
此MSDN论坛上有更多信息:
哪个州:
如果排序规则是SQL_Latin1_General_CP1_CI_AS或Latin1_General_CI_AS,您应该看到的区别很小,但两者都有比其他更快或更慢的实例。
Latin1_General_CI_AS: - Latin1-General,不区分大小写,重音 - 敏感,kanatype不敏感,宽度不敏感
SQL_Latin1_General_CP1_CI_AS: - Latin1-General,不区分大小写, 对Unicode非常敏感,对kanatype不敏感,对宽度不敏感 数据,SQL Server在代码页1252上对非Unicode数据进行排序
因此,在我看来,你不应该看到差异,特别是如果你的数据只是a-z0-9
答案 3 :(得分:5)
SELECT * FROM ::fn_helpcollations()
WHERE name IN (
'SQL_Latin1_General_CP1_CI_AS',
'Latin1_General_CI_AS'
)
...给出...
Latin1_General_CI_AS: Latin1-General,不区分大小写,区分重音,不区分kanatype,宽度不敏感
SQL_Latin1_General_CP1_CI_AS: Latin1-常规,不区分大小写,区分重音,对kanatype不敏感,对Unicode数据不区分宽度,对于非Unicode数据,SQL Server在代码页1252上排序52
因此,我推断使用的代码页是相同的(Latin1-General => 1252),因此 应该不会丢失数据 - 如果有什么要改变的话 - 转换它可能是排序顺序 - 这可能是无关紧要的。
答案 4 :(得分:-1)