Modifier le classement
J'ai besoin de changer le classement d'une de nos bases de données sur un serveur particulier de Latin1_General_CI_AS
à SQL_Latin1_General_CP1_CI_AI
pour qu'il corresponde au reste de nos bases de données.
Le problème
Cependant, lorsque j'essaie de le faire, j'obtiens l'erreur suivante:
Échec de ALTER DATABASE. Le classement par défaut de la base de données 'XxxxxXxxxxx' ne peut pas être défini sur SQL_Latin1_General_CP1_CI_AI. (Microsoft SQL Server, erreur: 5075)
Ma recherche
Ma recherche sur le sujet a révélé un certain nombre d'articles qui indiquent que j'ai besoin d'exporter toutes les données, de supprimer la base de données, de la recréer avec le bon classement, puis de réimporter les données.
Par exemple: Problème avec le changement de classement de la base de données (SQL Server 2008)
C'est évidemment une tâche importante, d'autant plus que les relations clés primaires-étrangères doivent être préservées et que notre base de données est assez volumineuse (plus de dix millions de lignes de données).
Ma question
Existe-t-il un moyen de modifier le classement d'une base de données SQL Server 2012 existante qui ne nécessite pas d'exporter et de réimporter toutes les données?
Sinon, existe-t-il des outils ou des scripts qui peuvent automatiser ce processus de manière fiable?
Ce qui suit fonctionne pour moi sur SQL Server 2012:
ALTER DATABASE CURRENT COLLATE SQL_Latin1_General_CP1_CI_AI;
La réponse acceptée dans la question liée n'est pas entièrement correcte, du moins pas pour SQL Server 2012. Elle dit:
Ahh, c'est l'un des pires problèmes de SQL Server: vous ne pouvez pas changer le classement une fois qu'un objet est créé (cela est vrai à la fois pour les tables et les bases de données ...).
Mais je pouvais juste changer le classement par défaut et j'ai des tables qui sont remplies. La page MSDN pour ALTER DATABASE indique dans la section "Remarques", sous "Modification du classement de la base de données":
Avant d'appliquer un classement différent à une base de données, assurez-vous que les conditions suivantes sont en place:
Vous êtes le seul actuellement à utiliser la base de données.
Aucun objet lié au schéma ne dépend du classement de la base de données.
Si les objets suivants, qui dépendent du classement de la base de données, existent dans la base de données, l'instruction ALTER DATABASE database_name COLLATE échouera. SQL Server renvoie un message d'erreur pour chaque objet bloquant l'action ALTER:
Fonctions et vues définies par l'utilisateur créées avec SCHEMABINDING.
Colonnes calculées.
VERIFIER les contraintes.
Fonctions table qui renvoient des tables avec des colonnes de caractères avec des classements hérités du classement par défaut de la base de données.
Donc, je suggère de vous assurer que la base de données est en mode mono-utilisateur et que si vous avez l'un de ces quatre éléments, vous:
MAIS, à ce stade, tout ce qui a été modifié est le classement par défaut de la base de données. Le classement de toutes les colonnes existantes dans les tables utilisateur (c'est-à-dire les tables non système) aura toujours le classement d'origine. Si vous voulez des colonnes de chaîne existantes - CHAR
, VARCHAR
, NCHAR
, NVARCHAR
, et les TEXT
et NTEXT
- pour prendre en charge le nouveau classement, vous devez modifier chacune de ces colonnes individuellement. Et, si des index sont définis sur ces colonnes, ces index devront d'abord être supprimés (la désactivation ne suffit pas) et recréés après le ALTER COLUMN
(autres dépendances qui empêcheraient le ALTER COLUMN
aurait déjà été supprimé afin d'obtenir le ALTER DATABASE
travailler). L'exemple ci-dessous illustre ce comportement:
Configuration du test
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;
Test 1: Modifier le classement des colonnes sans dépendances
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;
Le ALTER COLUMN
les instructions ci-dessus ont abouti.
Test 2: Modifier le classement des colonnes avec les dépendances
-- 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;
Cette fois, le ALTER COLUMN
l'instruction a reçu l'erreur suivante:
Msg 5074, niveau 16, état 1, ligne 60
L'index 'IX_ChangeCollationParent_ExtendedASCIIString' dépend de la colonne 'ExtendedASCIIString'.
Msg 4922, niveau 16, état 9, ligne 60
ALTER TABLE ALTER COLUMN ExtendedASCIIString a échoué car un ou plusieurs objets accèdent à cette colonne.
AUSSI, veuillez noter que le classement de certaines colonnes de chaîne dans les vues de catalogue système de portée base de données (par exemple sys.objects
, sys.columns
, sys.indexes
, etc.) passera au nouveau classement. Si votre code contient des JOIN à l'une de ces colonnes de chaîne (c'est-à-dire name
), vous pouvez alors commencer à obtenir des erreurs de non-concordance de classement jusqu'à ce que vous changiez le classement sur les colonnes de jointure dans vos tables utilisateur.
MISE À JOUR:
Si la modification du classement pour l'ensemble de l'instance est souhaitée ou une option, il existe une méthode plus simple qui contourne toutes ces restrictions. Il n'est pas documenté et donc non pris en charge (donc si cela ne fonctionne pas, Microsoft ne va pas aider). Cependant, il modifie le classement à tous les niveaux: instance, toutes les bases de données et toutes les colonnes de chaîne dans toutes les tables utilisateur. Il fait cela, et évite toutes les restrictions typiques, en mettant simplement à jour les métadonnées des tables, etc. pour avoir le nouveau classement. Il supprime puis recrée tous les index qui ont des colonnes de chaînes. Il existe également quelques nuances à cette méthode qui peuvent avoir un impact, mais qui peuvent être corrigées. Cette méthode est le -q
commutateur de ligne de commande de sqlservr.exe
. J'ai documenté tous les comportements, y compris la liste de toutes les zones potentiellement affectées en effectuant un changement de classement aussi vaste, dans le post suivant: