web-dev-qa-db-fra.com

Modifier les classements de toutes les colonnes de toutes les tables dans SQL Server

J'ai importé une base de données avec des données à comparer avec une autre base de données.

La base de données cible a un classement Latin1_General_CI_AS et la base de données source a SQL_Latin1_General_CP1_CI_AS.

J'ai modifié le classement de la base de données source en général en Latin1_General_CI_AS à l'aide de SQL Server Management Studio. Mais les tables et les colonnes à l'intérieur restent avec l'ancien classement.

Je sais que je peux changer une colonne en utilisant:

ALTER TABLE [table] 
ALTER COLUMN [column] VARCHAR(100) COLLATE Latin1_General_CI_AS

Mais je dois le faire pour toutes les tables et toutes les colonnes à l'intérieur.

Avant que je sache, commencez à écrire une procédure stockée qui lit toutes les tables et toutes les colonnes de type varchar et les modifie en boucle de curseur de table et de colonne ...

Est-ce que quelqu'un connaît un moyen plus simple ou est le seul moyen de le faire avec un script exécutant toutes les tables d'une procédure?

43
YvesR

N'ayant pas trouvé le moyen approprié, j'ai écrit un script pour le faire et je le partage ici pour ceux qui en ont besoin. Le script parcourt toutes les tables utilisateur et collecte les colonnes. Si le type de colonne est un type de caractère, il essaie de la convertir dans le classement donné.

Les colonnes doivent être libres d’index et de contraintes pour que cela fonctionne.

Si quelqu'un a encore une meilleure solution à cela s'il vous plaît poster!

DECLARE @collate nvarchar(100);
DECLARE @table nvarchar(255);
DECLARE @column_name nvarchar(255);
DECLARE @column_id int;
DECLARE @data_type nvarchar(255);
DECLARE @max_length int;
DECLARE @row_id int;
DECLARE @sql nvarchar(max);
DECLARE @sql_column nvarchar(max);

SET @collate = 'Latin1_General_CI_AS';

DECLARE local_table_cursor CURSOR FOR

SELECT [name]
FROM sysobjects
WHERE OBJECTPROPERTY(id, N'IsUserTable') = 1

OPEN local_table_cursor
FETCH NEXT FROM local_table_cursor
INTO @table

WHILE @@FETCH_STATUS = 0
BEGIN

    DECLARE local_change_cursor CURSOR FOR

    SELECT ROW_NUMBER() OVER (ORDER BY c.column_id) AS row_id
        , c.name column_name
        , t.Name data_type
        , c.max_length
        , c.column_id
    FROM sys.columns c
    JOIN sys.types t ON c.system_type_id = t.system_type_id
    LEFT OUTER JOIN sys.index_columns ic ON ic.object_id = c.object_id AND ic.column_id = c.column_id
    LEFT OUTER JOIN sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
    WHERE c.object_id = OBJECT_ID(@table)
    ORDER BY c.column_id

    OPEN local_change_cursor
    FETCH NEXT FROM local_change_cursor
    INTO @row_id, @column_name, @data_type, @max_length, @column_id

    WHILE @@FETCH_STATUS = 0
    BEGIN

        IF (@max_length = -1) OR (@max_length > 4000) SET @max_length = 4000;

        IF (@data_type LIKE '%char%')
        BEGIN TRY
            SET @sql = 'ALTER TABLE ' + @table + ' ALTER COLUMN ' + @column_name + ' ' + @data_type + '(' + CAST(@max_length AS nvarchar(100)) + ') COLLATE ' + @collate
            PRINT @sql
            EXEC sp_executesql @sql
        END TRY
        BEGIN CATCH
          PRINT 'ERROR: Some index or constraint rely on the column' + @column_name + '. No conversion possible.'
          PRINT @sql
        END CATCH

        FETCH NEXT FROM local_change_cursor
        INTO @row_id, @column_name, @data_type, @max_length, @column_id

    END

    CLOSE local_change_cursor
    DEALLOCATE local_change_cursor

    FETCH NEXT FROM local_table_cursor
    INTO @table

END

CLOSE local_table_cursor
DEALLOCATE local_table_cursor

GO
51
YvesR

Je ne suis donc pas satisfait de la réponse. J'étais chargé de mettre à niveau JIRA 6.4.x vers JIRA Software 7.x et je suis allé à ce problème particulier avec la collation de base de données et de colonne. 

Dans SQL Server, si vous ne supprimez pas les contraintes telles que la clé primaire ou la clé étrangère ou même les index, le script fourni ci-dessus en tant que réponse ne fonctionne pas du tout. Il va cependant changer ceux sans ces propriétés. C'est vraiment problématique, car je ne veux pas supprimer manuellement toutes les contraintes et les reconstituer. Cette opération pourrait probablement se solder par des erreurs. De l'autre côté, créer un script automatisant le changement peut prendre des siècles. 

J'ai donc trouvé un moyen de faire la migration simplement en utilisant SQL Management Studio. Voici la procédure: 

  • Renommez la base de données par quelque chose d'autre. Par exemple, le mien était "Jira", alors je l'ai renommé "JiraTemp". 
  • Créez une nouvelle base de données nommée "Jira" et assurez-vous de définir le bon classement. Il suffit de sélectionner la page "Options" et de modifier le classement.
  • Une fois créé, retournez à "JiraTemp", cliquez dessus avec le bouton droit de la souris, "Tâches -> Générer des scripts ...".
    • Sélectionnez "Script toute la base de données et tous les objets de base de données".
    • Sélectionnez "Enregistrer dans une nouvelle fenêtre de requête", puis sélectionnez "Avancé".
    • Modifier la valeur de "Script pour la version du serveur" pour la valeur souhaitée
    • Activer les "autorisations de niveau objet de script", "propriétaire du script" et "index de texte intégral de script"
    • Laissez tout le reste tel quel ou personnalisez-le si vous le souhaitez.
  • Une fois généré, supprimez la section "CREATE DATABASE". Remplacez "JiraTemp" par "Jira".
  • Exécutez le script. Toute la structure de la base de données et les autorisations de la base de données sont maintenant répliquées sur "Jira". 
  • Avant de copier les données, nous devons désactiver toutes les contraintes. Exécutez la commande suivante pour le faire dans la base de données "Jira": EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
  • Maintenant, les données doivent être transférées. Pour ce faire, cliquez simplement sur "JiraTemp", puis sélectionnez "Tâches -> Exporter les données ..."
    • Sélectionnez comme source de données et cible le fournisseur de base de données OLE pour SQL Server. 
    • La base de données source est "JiraTemp"
    • La base de données de destination est "Jira"
    • Le nom du serveur est techniquement identique pour la source et la destination (sauf si vous avez créé la base de données sur un autre serveur).
    • Sélectionnez "Copier les données d'une ou de plusieurs tables ou vues".
    • Sélectionnez toutes les tables sauf les vues. Puis, quand il est encore en surbrillance, cliquez sur "Modifier les correspondances". Cochez "Activer l'identité insérer"
    • Cliquez sur OK, sur Suivant, puis sur Terminer.
  • Le transfert de données peut prendre un certain temps. Une fois terminé, exécutez la commande suivante pour réactiver toutes les contraintes: exec sp_msforeachtable @command1="print '?'", @command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"

Une fois terminé, j'ai redémarré JIRA et mon classement dans la base de données était en ordre. J'espère que ça aide beaucoup de gens! 

32
David

Problème de longueur fixe nvarchar et ajout de NULL/NOT NULL

DECLARE @collate nvarchar(100);
DECLARE @table nvarchar(255);
DECLARE @column_name nvarchar(255);
DECLARE @column_id int;
DECLARE @data_type nvarchar(255);
DECLARE @max_length int;
DECLARE @row_id int;
DECLARE @sql nvarchar(max);
DECLARE @sql_column nvarchar(max);
DECLARE @is_Nullable bit;
DECLARE @null nvarchar(25);

SET @collate = 'Latin1_General_CI_AS';

DECLARE local_table_cursor CURSOR FOR

SELECT [name]
FROM sysobjects
WHERE OBJECTPROPERTY(id, N'IsUserTable') = 1

OPEN local_table_cursor
FETCH NEXT FROM local_table_cursor
INTO @table

WHILE @@FETCH_STATUS = 0
BEGIN

    DECLARE local_change_cursor CURSOR FOR

    SELECT ROW_NUMBER() OVER (ORDER BY c.column_id) AS row_id
        , c.name column_name
        , t.Name data_type
        , c.max_length
        , c.column_id
        , c.is_nullable
    FROM sys.columns c
    JOIN sys.types t ON c.system_type_id = t.system_type_id
    LEFT OUTER JOIN sys.index_columns ic ON ic.object_id = c.object_id AND ic.column_id = c.column_id
    LEFT OUTER JOIN sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
    WHERE c.object_id = OBJECT_ID(@table)
    ORDER BY c.column_id

    OPEN local_change_cursor
    FETCH NEXT FROM local_change_cursor
    INTO @row_id, @column_name, @data_type, @max_length, @column_id, @is_nullable

    WHILE @@FETCH_STATUS = 0
    BEGIN

        IF (@max_length = -1) SET @max_length = 4000;
        set @null=' NOT NULL'
        if (@is_nullable = 1) Set @null=' NULL'
        if (@Data_type='nvarchar') set @max_length=cast(@max_length/2 as bigint)
        IF (@data_type LIKE '%char%')
        BEGIN TRY
            SET @sql = 'ALTER TABLE ' + @table + ' ALTER COLUMN [' + rtrim(@column_name) + '] ' + @data_type + '(' + CAST(@max_length AS nvarchar(100)) +  ') COLLATE ' + @collate + @null
            PRINT @sql
            EXEC sp_executesql @sql
        END TRY
        BEGIN CATCH
          PRINT 'ERROR: Some index or contraint rely on the column ' + @column_name + '. No conversion possible.'
          PRINT @sql
        END CATCH

        FETCH NEXT FROM local_change_cursor
        INTO @row_id, @column_name, @data_type, @max_length, @column_id, @is_Nullable

    END

    CLOSE local_change_cursor
    DEALLOCATE local_change_cursor

    FETCH NEXT FROM local_table_cursor
    INTO @table

END

CLOSE local_table_cursor
DEALLOCATE local_table_cursor

GO
15
Pieter Mink

Pour ce faire, j'ai une solution facile qui fonctionne pour moi.

  1. Créez une nouvelle base de données avec le nouveau classement.
  2. Exportez les données de la base de données d'origine en mode script.
  3. Importez le contenu dans la nouvelle base de données à l'aide du script (renommez la phrase USE en nouvelle base).

Cependant, vous devez faire preuve de prudence si votre base de données a des déclencheurs, des procédures ou similaires - davantage que des données et des tables.

5
dlopezgonzalez

Problème de longueur fixe nvarchar (inclure max), texte inclus et ajout de NULL/NOT NULL.

USE [put your database name here];

begin tran

DECLARE @collate nvarchar(100);
DECLARE @table nvarchar(255);
DECLARE @column_name nvarchar(255);
DECLARE @column_id int;
DECLARE @data_type nvarchar(255);
DECLARE @max_length int;
DECLARE @max_length_str nvarchar(100);
DECLARE @is_nullable bit;
DECLARE @row_id int;
DECLARE @sql nvarchar(max);
DECLARE @sql_column nvarchar(max);

SET @collate = 'Latin1_General_CI_AS';

DECLARE local_table_cursor CURSOR FOR

SELECT [name]
FROM sysobjects
WHERE OBJECTPROPERTY(id, N'IsUserTable') = 1
ORDER BY [name]

OPEN local_table_cursor
FETCH NEXT FROM local_table_cursor
INTO @table

WHILE @@FETCH_STATUS = 0
BEGIN

    DECLARE local_change_cursor CURSOR FOR

    SELECT ROW_NUMBER() OVER (ORDER BY c.column_id) AS row_id
        , c.name column_name
        , t.Name data_type
        , col.CHARACTER_MAXIMUM_LENGTH
        , c.column_id
        , c.is_nullable
    FROM sys.columns c
    JOIN sys.types t ON c.system_type_id = t.system_type_id
    JOIN INFORMATION_SCHEMA.COLUMNS col on col.COLUMN_NAME = c.name and c.object_id = OBJECT_ID(col.TABLE_NAME)
    LEFT OUTER JOIN sys.index_columns ic ON ic.object_id = c.object_id AND ic.column_id = c.column_id
    LEFT OUTER JOIN sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
    WHERE c.object_id = OBJECT_ID(@table) AND (t.Name LIKE '%char%' OR t.Name LIKE '%text%') 
    AND c.collation_name <> @collate
    ORDER BY c.column_id

    OPEN local_change_cursor
    FETCH NEXT FROM local_change_cursor
    INTO @row_id, @column_name, @data_type, @max_length, @column_id, @is_nullable

    WHILE @@FETCH_STATUS = 0
    BEGIN

        set @max_length_str = @max_length
        IF (@max_length = -1) SET @max_length_str = 'max'
        IF (@max_length > 4000) SET @max_length_str = '4000'

        BEGIN TRY
            SET @sql =
            CASE 
                WHEN @data_type like '%text%' 
                THEN 'ALTER TABLE ' + @table + ' ALTER COLUMN [' + @column_name + '] ' + @data_type + ' COLLATE ' + @collate + ' ' + CASE WHEN @is_nullable = 0 THEN 'NOT NULL' ELSE 'NULL' END
                ELSE 'ALTER TABLE ' + @table + ' ALTER COLUMN [' + @column_name + '] ' + @data_type + '(' + @max_length_str + ') COLLATE ' + @collate + ' ' + CASE WHEN @is_nullable = 0 THEN 'NOT NULL' ELSE 'NULL' END
            END
            --PRINT @sql
            EXEC sp_executesql @sql
        END TRY
        BEGIN CATCH
          PRINT 'ERROR (' + @table + '): Some index or constraint rely on the column ' + @column_name + '. No conversion possible.'
          --PRINT @sql
        END CATCH

        FETCH NEXT FROM local_change_cursor
        INTO @row_id, @column_name, @data_type, @max_length, @column_id, @is_nullable

    END

    CLOSE local_change_cursor
    DEALLOCATE local_change_cursor

    FETCH NEXT FROM local_table_cursor
    INTO @table

END

CLOSE local_table_cursor
DEALLOCATE local_table_cursor

commit tran

GO

Remarque: dans le cas où vous devez simplement modifier une condition d'utilisation de collation spécifique comme celle-ci:

WHERE c.object_id = OBJECT_ID(@table) AND (t.Name LIKE '%char%' OR t.Name LIKE '%text%') 
    AND c.collation_name = 'collation to change'

par exemple.NOTthe: AND c.collation_name <> @collate

Dans mon cas, j'avais un classement correct/spécifié de certaines colonnes et je ne voulais pas les changer.

1
Pavlo

Pour ceux qui recherchent cette solution et qui utilisent PHPMyAdmin, une option se trouve au bas de l'onglet "Opérations" (cliquez d'abord sur une base de données); deux cases à cocher (une apparaît lorsque la première est cochée):

  • Changer tous les classements des tables
  • Changer toutes les collations des colonnes des tables

Semble exécuter un script semblable à ceux affichés; la console affiche la dernière commande exécutée:

ALTER TABLE `DB_NAME`.`LAST_TABLE_IN_DB`DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci
0
SmokeyTBear

Le script suivant fonctionnera avec le schéma de table ainsi que les derniers types tels que (MAX), IMAGE, etc., modifiez votre type de classement en fonction de vos besoins sur cette ligne (SET @collate = 'DATABASE_DEFAULT';

SQL SCRIPT ICI:

BEGIN
DECLARE @collate nvarchar(100);
declare @schema nvarchar(255);
DECLARE @table nvarchar(255);
DECLARE @column_name nvarchar(255);
DECLARE @column_id int;
DECLARE @data_type nvarchar(255);
DECLARE @max_length varchar(100);
DECLARE @row_id int;
DECLARE @sql nvarchar(max);
DECLARE @sql_column nvarchar(max);

SET @collate = 'DATABASE_DEFAULT';

DECLARE tbl_cursor CURSOR FOR SELECT (s.[name])schemaName, (o.[name])[tableName]
FROM sysobjects sy 
INNER JOIN sys.objects  o on o.name = sy.name
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE OBJECTPROPERTY(sy.id, N'IsUserTable') = 1

OPEN tbl_cursor FETCH NEXT FROM tbl_cursor INTO @schema,@table

WHILE @@FETCH_STATUS = 0
BEGIN
    DECLARE tbl_cursor_changed CURSOR FOR
        SELECT ROW_NUMBER() OVER (ORDER BY c.column_id) AS row_id
            , c.name column_name
            , t.Name data_type
            , c.max_length
            , c.column_id
        FROM sys.columns c
        JOIN sys.types t ON c.system_type_id = t.system_type_id
        LEFT OUTER JOIN sys.index_columns ic ON ic.object_id = c.object_id AND ic.column_id = c.column_id
        LEFT OUTER JOIN sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
    WHERE c.object_id like OBJECT_ID(@schema+'.'+@table)
    ORDER BY c.column_id


    OPEN tbl_cursor_changed 
     FETCH NEXT FROM tbl_cursor_changed
    INTO @row_id, @column_name, @data_type, @max_length, @column_id



    WHILE @@FETCH_STATUS = 0
    BEGIN
    IF (@max_length = -1) SET @max_length = 'MAX';
        IF (@data_type LIKE '%char%')
        BEGIN TRY
            SET @sql = 'ALTER TABLE ' +@schema+'.'+ @table + ' ALTER COLUMN ' + @column_name + ' ' + @data_type + '(' + CAST(@max_length AS nvarchar(100)) + ') COLLATE ' + @collate
            print @sql
            EXEC sp_executesql @sql
        END TRY
        BEGIN CATCH
          PRINT 'ERROR:'
          PRINT @sql
        END CATCH

        FETCH NEXT FROM tbl_cursor_changed
        INTO @row_id, @column_name, @data_type, @max_length, @column_id

    END

    CLOSE tbl_cursor_changed
    DEALLOCATE tbl_cursor_changed

    FETCH NEXT FROM tbl_cursor
    INTO @schema, @table

END

CLOSE tbl_cursor
DEALLOCATE tbl_cursor

PRINT 'Collation For All Tables Done!'
0
Haseeb