web-dev-qa-db-ja.com

SQL Server 2012データベースの照合順序を変更する

変更照合

特定のサーバー上のデータベースのいずれかの照合順序を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)

私の研究

このトピックに関するグーグル検索では、すべてのデータをエクスポートし、データベースを削除し、正しい照合順序でデータベースを再作成してからデータを再インポートする必要があることを示す多くの記事が明らかになりました。

例: データベース照合順序変更の問題(SQL Server 2008)

明らかに、これは重要なタスクです。特に、主キーと外部キーの関係を保持する必要があり、データベースが非常に大きい(1000万を超えるデータ行)ためです。

私の質問

すべてのデータをエクスポートおよび再インポートする必要のない既存のSQL Server 2012データベースの照合順序を変更する方法はありますか?

または、このプロセスを信頼性の高い方法で自動化できるツールまたはスクリプトがありますか?

12
Mark Micallef

以下は、SQL Server 2012で動作します。

ALTER DATABASE CURRENT COLLATE SQL_Latin1_General_CP1_CI_AI;

リンクされた質問で受け入れられた答えは、少なくともSQL Server 2012については完全には正しくありません。

ああ、これはSQL Serverの最悪の問題の1つです。オブジェクトが作成されたら、照合順序を変更することはできません(テーブルとデータベースの両方に当てはまります...)。

しかし、デフォルトの照合を変更することができただけで、テーブルが設定されています。 ALTER DATABASE のMSDNページには、「備考」セクションの「データベース照合の変更」に記載されています。

別の照合をデータベースに適用する前に、次の条件が整っていることを確認してください。

  1. 現在データベースを使用しているのはあなただけです。

  2. データベースの照合に依存するスキーマバインドオブジェクトはありません。

    データベース照合に依存する以下のオブジェクトがデータベースに存在する場合、ALTER DATABASEdatabase_nameCOLLATEステートメントは失敗します。 SQL Serverは、ALTERアクションをブロックしているオブジェクトごとにエラーメッセージを返します。

    • SCHEMABINDINGで作成されたユーザー定義の関数とビュー。

    • 計算列。

    • チェック制約。

    • デフォルトのデータベース照合から継承された照合を持つ文字列を持つテーブルを返すテーブル値関数。

したがって、データベースがシングルユーザーモードになっていること、およびこれらの4つのアイテムのいずれかがある場合は、次のことを確認することをお勧めします。

  • それらを落とす
  • 照合を変更する
  • そして、それらを再度追加します

BUT、その時点で変更されているのは、データベースのデフォルトの照合のみです。ユーザーテーブル(つまり、非システムテーブル)の既存の列の照合順序には、元の照合順序がそのまま残ります。既存の文字列列が必要な場合-CHARVARCHARNCHARNVARCHAR、および非推奨のTEXTおよびNTEXT-新しい照合順序を使用するには、これらの各列を個別に変更する必要があります。そして、それらの列に定義されたインデックスがある場合、それらのインデックスは最初に削除する必要があります(無効にするだけでは十分ではありません)ALTER COLUMNALTER COLUMNALTER 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ステートメントは次のエラーを受け取りました。

メッセージ5074、レベル16、状態1、行60
インデックス「IX_ChangeCollat​​ionParent_ExtendedASCIIString」は列「ExtendedASCIIString」に依存しています。
メッセージ4922、レベル16、状態9、行60
ALTER TABLE ALTER COLUMN ExtendedASCIIStringは、1つ以上のオブジェクトがこの列にアクセスするために失敗しました。

ALSO、データベーススコープシステムカタログビューの一部の文字列列の照合(例:sys.objectssys.columnssys.indexesなど)は新しい照合に変更されます。コードにこれらの文字列列(つまりname)のいずれかにJOINがある場合、ユーザーテーブルの結合列の照合順序を変更するまで照合順序の不一致エラーが発生する可能性があります。

UPDATE:

インスタンス全体の照合順序を変更することが望ましい場合、またはオプションである場合、これらの制限をすべてバイパスする簡単な方法があります。文書化されていないため、サポートされていません(したがって、動作しない場合、Microsoftは支援しません)。ただし、すべてのレベル(インスタンス、すべてのデータベース、すべてのユーザーテーブルのすべての文字列列)で照合順序が変更されます。これを実行し、テーブルのメタデータを更新するなどして新しいCollat​​ionを使用することで、一般的な制限をすべて回避します。次に、文字列列を持つすべてのインデックスを削除して再作成します。この方法には、影響はあるかもしれないが修正可能な微妙なニュアンスもあります。このメソッドは、-qsqlservr.exeコマンドラインスイッチです。次の投稿では、このような大規模な照合の変更を行うことにより、影響を受ける可能性のあるすべての領域をリストするなど、すべての動作を文書化しました。

すべてのユーザーデータベースのインスタンス、データベース、およびすべての列の照合順序を変更する:何が間違っている可能性がありますか?

18
Solomon Rutzky