SQL Server SQL_Latin1_General_CP1_CI_AS可以安全地转换为Latin1_General_CI_AS吗?

Kra*_*ram 22 sql sql-server collation

我们有一个遗留数据库,其中一些(较旧的)列使用"SQL_Latin1_General_CP1_CI_AS",最近的更改使用了"Latin1_General_CI_AS".

这是一个痛苦,因为连接需要额外的COLLATE语句才能工作.

我想把所有内容都改为"Latin1_General_CI_AS".从我可以收集的内容来看,它们或多或少是相同的排序规则,在此过程中我不会丢失数据......

有谁知道是否是这种情况?

Zar*_*eth 31

这是一个更完整的答案:

https://www.olcot.co.uk/revised-difference-between-collat​​ion-sql_latin1_general_cp1_ci_as-and-latin1_general_ci_as/

这些排序规则之间的关键区别在于它们如何应用字符扩展规则.某些拉丁字符可能会扩展为多个字符.在处理非Unicode文本时,SQL_xxxx排序规则可能会忽略这些字符扩展,但会将它们应用于unicode文本.因此:当使用一个排序规则与另一个排序规则时,连接,排序和比较可能会返回不同的结果.

例:

Latin1_General_CI_AS这两个语句下返回相同的记录集,ß扩展为ss.

SELECT * FROM MyTable3 WHERE Comments = 'strasse'
SELECT * FROM MyTable3 WHERE Comments = 'straße'
Run Code Online (Sandbox Code Playgroud)

当使用SQL_Latin1_General_CP1_CI_AS上述语句时返回不同的记录,因为它ß被视为不同的字符ss.

  • @Hannobo(和 Zarepheth):不要转换为“VARCHAR”,因为这可能会导致数据丢失。您需要使用匈牙利语或二进制排序规则,因为它们是唯一不等于这些特定字符的排序规则。因此,请尝试“COLLATE Hungarian_Technical_100_CI_AS_SC”或“COLLATE Latin1_General_100_BIN2”。有关更多详细信息,请参阅我的回答[此处](/sf/answers/3001854691/)和[此处](/sf/answers/1897928931/)。此外,变量(和字符串文字)始终具有当前数据库的默认排序规则,并且不能指定不同的排序规则。 (3认同)
  • +1 用于查找和提及字符扩展。我在我的 [answer](http://stackoverflow.com/a/34342009/577765) 中包含了它(以及提到它的 Unicode 文档的链接),并添加了更多需要注意的项目:-)。 (2认同)

Sol*_*zky 24

如果您要更改数据库的排序规则,那么您肯定应该了解一些内容,以便您可以相应地进行规划:

  • 关于数据丢失的可能性:

    • 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};
    
    Run Code Online (Sandbox Code Playgroud)

    请务必指定当前正在使用的完全相同的数据类型和NULL/ NOT NULL设置,否则如果它们不是默认值,它们可以恢复为默认值.之后,如果任何字符串列上的任何索引刚刚更改了其排序规则,那么您需要重建这些索引.

  • 更改数据库的默认排序规则将改变某些特定数据库的元数据的整理,如name在这两个领域sys.objects,sys.columns,sys.indexes,等过滤对局部变量或字符串文字,这些制度的意见将不会是一个问题,因为整理会双方都在变化.但是,如果将任何本地系统视图连接到字符串字段上的临时表,并且本地数据库之间的数据库级排序规则tempdb不匹配,则会出现"排序规则不匹配"错误.下面将讨论这一问题以及补救措施.

  • 这两个Collat​​ions之间的一个区别在于它们如何为VARCHAR数据排序某些字符(这不会影响NVARCHAR数据).非EBCDIC SQL_Collat​​ions对VARCHAR数据使用所谓的"String Sort" ,而所有其他Collat​​ions,甚至NVARCHAR非EBCDIC SQL_Collat​​ions的数据都使用所谓的"Word Sort".不同之处在于,在"单词排序"中,短划线-和撇号'(可能还有一些其他字符?)的权重非常低,除非字符串中没有其他差异,否则基本上会被忽略.要查看此行为,请运行以下命令:

    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
    
    Run Code Online (Sandbox Code Playgroud)

    返回:

    String Sort
    -----------
    a'kb
    a-f
    a_e
    aa
    ac
    ah
    aka
    akc
    am
    ar
    
    Run Code Online (Sandbox Code Playgroud)

    和:

    Word Sort
    ---------
    a_e
    aa
    ac
    a-f
    ah
    aka
    a'kb
    akc
    am
    ar
    
    Run Code Online (Sandbox Code Playgroud)

    虽然你将"失去""字符串排序"行为,但我不确定我会称之为"特征".这种行为被认为是不合需要的(事实证明它没有被提到任何Windows排序规则中).然而,这两个归类(再次,只是为了非EBCDIC之间的行为的一定的差异VARCHAR数据),并且可能必须基于"字符串排序"行为的代码和/或客户的期望.这需要测试您的代码并可能进行研究,以确定这种行为变化是否会对用户产生任何负面影响.

  • SQL_Latin1_General_CP1_CI_AS和之间的另一个区别Latin1_General_100_CI_AS是能够对数据进行扩展VARCHAR(NVARCHAR数据已经可以为大多数SQL_Collat​​ions 执行这些操作),例如处理æ就好像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;
    
    Run Code Online (Sandbox Code Playgroud)

    返回:

    Latin1_General_100_CI_AS
    
    Run Code Online (Sandbox Code Playgroud)

    你在这里"失败"的唯一一件事就是无法进行这些扩展.一般来说,这是迁移到Windows排序规则的另一个好处.但是,就像"字符串排序"到"字排序"移动一样,同样谨慎适用:它是两个排序规则之间行为的明确差异(同样,仅用于VARCHAR数据),并且您可能有代码和/或客户基于没有这些映射的期望.这需要测试您的代码并可能进行研究,以确定这种行为变化是否会对用户产生任何负面影响.

    (首先在@ Zarepheth的答案中注明并在此处扩展)

  • 另一个区别(也就是移动到Windows排序规则的好处)是过滤VARCHARNVARCHAR文字/变量/列上编制索引的列,您将不再使VARCHAR列上的索引无效.这是由于Windows Collat​​ions对两者VARCHARNVARCHAR数据使用相同的Unicode排序和比较规则.由于两种类型之间的排序顺序相同,因此当VARCHAR数据转换为NVARCHAR(由于数据类型优先级而显式或隐式)时,索引中的项的顺序仍然有效.有关此行为的更多详细信息,请参阅我的帖子:混合VARCHAR和NVARCHAR类型时对索引的影响.

  • 服务器级Collat​​ion用于设置系统数据库的排序规则,其中包括[model].该[model]数据库作为模板来创建新的数据库,其中包括[tempdb]在每个服务器启动.因此,如果数据库的默认排序规则实例的默认排序规则不匹配,并且您将本地表连接到字符串字段上的临时表,则会出现排序规则不匹配错误.幸运的是,有一种简单的方法可以纠正CREATE #TempTable执行时"当前"的数据库之间的整理差异[tempdb].创建临时表时,使用COLLATE子句声明排序规则(在字符串列上)并使用特定排序规则(如果您知道数据库将始终使用该排序规则),或者DATABASE_DEFAULT(如果您不总是知道排序规则)此代码将执行的DB):

    CREATE TABLE #Temp (Col1 NVARCHAR(40) COLLATE DATABASE_DEFAULT);
    
    Run Code Online (Sandbox Code Playgroud)

    这对于表变量不是必需的,因为它们从"当前"数据库获得其默认排序规则.但是,如果您同时拥有表变量和临时表并将它们连接到字符串字段,那么您将需要使用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
    
    Run Code Online (Sandbox Code Playgroud)
  • 此外,虽然这个问题询问不区分大小写的排序规则,但应注意的是,如果别人正在做一个类似的变化,但使用区分大小写的排序规则,则SQL Server排序规则和Windows排序规则的另一个区别,对于VARCHAR唯一的数据,是哪种情况先排序.这意味着,如果您同时拥有Aa,则SQL_Collat​​ions将A在之前排序a,而非SQL_Collat​​ions(以及SQL_处理NVARCHAR数据时的Collat​​ions )将a在之前排序A.

有关更改数据库或整个实例的排序规则的更多信息和详细信息,请参阅我的帖子:
更改所有用户数据库中的实例,数据库和所有列的排序规则:可能出错的原因是什么?

有关使用字符串和排序规则的更多信息,请访问:排序规则信息


dun*_*nos 15

这个MSDN论坛有更多信息:

http://social.msdn.microsoft.com/Forums/en-US/sqlgetstarted/thread/196b4586-1338-434d-ba8c-49fa3c9bdeeb/

哪个州:

如果排序规则是SQL_Latin1_General_CP1_CI_AS或Latin1_General_CI_AS,您应该看到的区别很小,但两者都有比其他更快或更慢的实例.

Latin1_General_CI_AS: - Latin1-一般,不区分大小写,区分重音,不区分kanatype,宽度不敏感

SQL_Latin1_General_CP1_CI_AS: - Latin1-常规,不区分大小写,区分重音,对kanatype不敏感,对Unicode数据不区分宽度,对于非Unicode数据,在代码页1252上的SQL Server排序顺序52

因此,在我看来,你不应该看到差别,特别是如果你的数据只是a-z0-9

  • _“你应该看到很少的差异”_除非你想将 INFORMATION_SCHEMA 的结果与临时表连接或比较,而 AzureSQL 说不能。 (2认同)

Wil*_*l A 5

SELECT * FROM ::fn_helpcollations()
WHERE name IN (
'SQL_Latin1_General_CP1_CI_AS',
'Latin1_General_CI_AS'
)
Run Code Online (Sandbox Code Playgroud)

...给...

Latin1_General_CI_AS:Latin1-一般,不区分大小写,区分重音,不区分kanatype,宽度不敏感

SQL_Latin1_General_CP1_CI_AS:Latin1-常规,不区分大小写,区分重音,对kanatype不敏感,对Unicode数据不区分宽度,对于非Unicode数据,SQL Server在代码页1252上排序52

所以从这里,我推断使用的代码页是相同的(Latin1-General => 1252),所以你应该不会遇到数据丢失 - 如果有什么要改变转换后它可能是排序顺序 - 这是可能无关紧要.