更改SQL Server 2012数据库的排序规则

时间:2014-10-01 01:46:35

标签: sql-server collation

更改整理

我需要将特定服务器上某个数据库的排序规则从Latin1_General_CI_AS更改为SQL_Latin1_General_CP1_CI_AI,以便与其他数据库匹配。

Alter Collation Dialog - SQL Server 2012 R2

问题

但是,当我尝试这样做时,我收到以下错误:

  

ALTER DATABASE失败。数据库'XxxxxXxxxxx'的默认排序规则不能设置为SQL_Latin1_General_CP1_CI_AI。 (Microsoft SQL Server,错误:5075)

我的研究

我在Google搜索主题时发现了一些文章,表明我需要导出所有数据,删除数据库,使用正确的排序规则重新创建数据,然后重新导入数据。

例如:Problem with database collation change (SQL Server 2008)

显然这是一项重要的任务,特别是因为必须保留主外键关系,而且我们的数据库非常庞大(超过一千万个数据行)。

我的问题

有没有办法更改现有SQL Server 2012数据库的排序规则,不需要导出和重新导入所有数据?

或者,是否有一些工具或脚本能够以可靠的方式自动执行此过程?

2 个答案:

答案 0 :(得分:13)

以下适用于SQL Server 2012:

ALTER DATABASE CURRENT COLLATE SQL_Latin1_General_CP1_CI_AI;

链接问题中接受的答案并不完全正确,至少不适用于SQL Server 2012.它说:

  

啊,这是SQL Server中最严重的问题之一:一旦创建了对象,就无法更改排序规则(对于表和数据库都是如此......)。

但是我只能更改默认排序规则并且我已经填充了表格。 “备注”部分中“更改数据库归类”下的ALTER DATABASE个状态的MSDN页面:

  

在将不同的排序规则应用于数据库之前,请确保满足以下条件:

     
      
  1. 您是目前唯一使用该数据库的人。

  2.   
  3. 没有架构绑定对象取决于数据库的整理。

         

    如果数据库中存在依赖于数据库排序规则的以下对象,则ALTER DATABASE database_name COLLATE语句将失败。 SQL Server将为阻止ALTER操作的每个对象返回错误消息:

         
        
    • 使用SCHEMABINDING创建的用户定义函数和视图。

    •   
    • 计算列。

    •   
    • 检查约束。

    •   
    • 返回带有字符列的表的表值函数,其中的排序规则继承自默认数据库排序规则。

    •   
  4.   

所以,我建议确保数据库处于单用户模式,如果你有这四个项目中的任何一个,那么你:

  • 放弃他们
  • 更改整理
  • 然后重新添加

但是,此时所有已更改的内容都是数据库的默认排序规则。用户表(即非系统表)中任何现有列的排序仍将具有原始排序规则。如果您想要现有的字符串列 - CHARVARCHARNCHARNVARCHAR以及已弃用的TEXTNTEXT - 在新的排序规则上,您需要单独更改每个列。并且,如果在这些列上定义了任何索引,则需要首先删除这些索引(禁用是不够的)并在ALTER COLUMN之后再次创建(其他依赖会阻止ALTER COLUMN已被删除,以使ALTER DATABASE工作。以下示例说明了此行为:

测试设置

USE [tempdb];
SET NOCOUNT ON;

CREATE TABLE dbo.ChangeCollationParent
(
  [ChangeCollationParentID] INT NOT NULL IDENTITY(1, 1)
                    CONSTRAINT [PK_ChangeCollationParent]  PRIMARY KEY,
  ExtendedASCIIString VARCHAR(50) COLLATE Latin1_General_CI_AS NULL,
  UnicodeString NVARCHAR(50) COLLATE Latin1_General_CI_AS NULL
);

CREATE TABLE dbo.ChangeCollationChild
(
  [ChangeCollationChildID] INT NOT NULL IDENTITY(1, 1)
                    CONSTRAINT [PK_ChangeCollationChild]  PRIMARY KEY,
  [ChangeCollationParentID] INT NULL
                    CONSTRAINT [FK_ChangeCollationChild_ChangeCollationParent] FOREIGN KEY
                         REFERENCES dbo.ChangeCollationParent([ChangeCollationParentID]),
  ExtendedASCIIString VARCHAR(50) COLLATE Latin1_General_CI_AS NULL,
  UnicodeString NVARCHAR(50) COLLATE Latin1_General_CI_AS NULL
);

INSERT INTO dbo.ChangeCollationParent ([ExtendedASCIIString], [UnicodeString])
VALUES ('test1' + CHAR(200), N'test1' + NCHAR(200));
INSERT INTO dbo.ChangeCollationParent ([ExtendedASCIIString], [UnicodeString])
VALUES ('test2' + CHAR(170), N'test2' + NCHAR(170));


INSERT INTO dbo.ChangeCollationChild
         ([ChangeCollationParentID], [ExtendedASCIIString], [UnicodeString])
VALUES (1, 'testA ' + CHAR(200), N'testA ' + NCHAR(200));
INSERT INTO dbo.ChangeCollationChild
         ([ChangeCollationParentID], [ExtendedASCIIString], [UnicodeString])
VALUES (1, 'testB ' + CHAR(170), N'testB ' + NCHAR(170));

SELECT * FROM dbo.ChangeCollationParent;
SELECT * FROM dbo.ChangeCollationChild;

测试1:更改列没有依赖关系的排序

ALTER TABLE dbo.ChangeCollationParent
  ALTER COLUMN [ExtendedASCIIString] VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AI NULL;
ALTER TABLE dbo.ChangeCollationParent
  ALTER COLUMN [UnicodeString] NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AI NULL;

ALTER TABLE dbo.ChangeCollationChild
  ALTER COLUMN [ExtendedASCIIString] VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AI NULL;
ALTER TABLE dbo.ChangeCollationChild
  ALTER COLUMN [UnicodeString] NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AI NULL;

SELECT * FROM dbo.ChangeCollationParent;
SELECT * FROM dbo.ChangeCollationChild;

上述ALTER COLUMN语句成功完成。

测试2:更改列具有依赖关系的排序

-- First, create an index:
CREATE NONCLUSTERED INDEX [IX_ChangeCollationParent_ExtendedASCIIString]
  ON dbo.ChangeCollationParent ([ExtendedASCIIString] ASC);

-- Next, change the Collation back to the original setting:
ALTER TABLE dbo.ChangeCollationParent
  ALTER COLUMN [ExtendedASCIIString] VARCHAR(50) COLLATE Latin1_General_CI_AS NULL;

这次,ALTER COLUMN语句收到以下错误:

  

Msg 5074,Level 16,State 1,Line 60
  索引'IX_ChangeCollat​​ionParent_ExtendedASCIIString'依赖于列'ExtendedASCIIString'。
  Msg 4922,Level 16,State 9,Line 60
  ALTER TABLE ALTER COLUMN ExtendedASCIIString失败,因为一个或多个对象访问此列。

ALSO,请注意数据库范围的系统目录视图中的一些字符串列的整理(例如sys.objectssys.columnssys.indexes等)将更改为新的排序规则。如果您的代码具有任何这些字符串列的JOIN(即name),那么您可能会开始获取排序规则不匹配错误,直到更改用户表中连接列的排序规则。

<强>更新

如果希望更改整个实例的排序规则或选项,则可以使用更简单的方法绕过所有这些限制。它没有文档,因此不受支持(因此,如果它不起作用,微软将不会提供帮助)。但是,它会更改所有级别的排序规则:实例,所有数据库以及所有用户表中的所有字符串列。它通过简单地更新表的元数据等来实现这一点并避免所有典型的限制,以获得新的排序规则。然后它会删除并重新创建具有字符串列的所有索引。此方法也有一些细微差别可能会产生影响,但可以修复。此方法是-q的{​​{1}}命令行开关。我已记录了所有行为,包括通过执行如此广泛的整理更改来列出所有可能受影响的区域,在以下帖子中:

Changing the Collation of the Instance, the Databases, and All Columns in All User Databases: What Could Possibly Go Wrong?

答案 1 :(得分:0)

对于其他遇到此问题的人,解决方案是在更改排序规则之前将DB设置为single_user模式,然后在其后再次设置multi_user模式。 在设置多用户模式之前,请确保不关闭连接!