web-dev-qa-db-ja.com

SQL Serverのすべてのテーブルのすべての列の照合順序を変更する

別のデータベースと比較するために、いくつかのデータを含むデータベースをインポートしました。

ターゲットデータベースには照合Latin1_General_CI_ASがあり、ソースデータベースにはSQL_Latin1_General_CP1_CI_ASがあります。

SQL Server Management Studioを使用して、一般的にソースデータベースの照合をLatin1_General_CI_ASに変更しました。ただし、内部のテーブルと列は古い照合順序のままです。

私は次を使用して列を変更できることを知っています:

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

しかし、内部のすべてのテーブルとすべての列に対してこれを行う必要があります。

私が知る前に、すべてのテーブルとタイプvarcharのすべての列を読み取り、テーブルと列カーソルループでそれらを変更するストアドプロシージャを書き始めます...

誰でも簡単な方法を知っていますか、またはプロシージャ内のすべてのテーブルを実行するスクリプトでこれを行う唯一の方法ですか?

47
YvesR

適切な方法が見つからなかったため、それを行うスクリプトを作成しました。必要な人のためにここで共有しています。スクリプトはすべてのユーザーテーブルを実行し、列を収集します。列型が文字型の場合、指定された照合に変換しようとします。

これを機能させるには、列にインデックスと制約がない必要があります。

誰かがまだこれに対するより良い解決策を持っているなら、それを投稿してください!

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
55
YvesR

だから、ここで私はもう一度、答えに満足していません。 JIRA 6.4.xをJIRA Software 7.xにアップグレードすることを任されましたが、データベースと列の照合に関する特定の問題に取り組みました。

SQL Serverでは、プライマリキー、外部キー、またはインデックスなどの制約を削除しないと、上記の回答として提供されたスクリプトはまったく機能しません。ただし、これらのプロパティがない場合は変更されます。すべての制約を手動で削除して元に戻したくないので、これは本当に問題です。その操作はおそらくエラーで終わる可能性があります。一方、変更を自動化するスクリプトを作成するには、時間がかかる場合があります。

そこで、SQL Management Studioを使用するだけで移行を行う方法を見つけました。手順は次のとおりです。

  • データベースの名前を別の名前に変更します。たとえば、私のものは「Jira」だったので、名前を「JiraTemp」に変更しました。
  • 「Jira」という名前の新しいデータベースを作成し、正しい照合を設定してください。 「オプション」ページを選択し、照合を変更するだけです。
  • 作成したら、「JiraTemp」に戻って右クリックし、「タスク->スクリプトの生成...」
    • 「データベース全体とすべてのデータベースオブジェクトのスクリプト」を選択します。
    • [新しいクエリウィンドウに保存]を選択し、[詳細設定]を選択します
    • 「サーバーバージョンのスクリプト」の値を目的の値に変更します
    • 「スクリプトオブジェクトレベルの権限」、「スクリプト所有者」、および「スクリプトフルテキストインデックス」を有効にします。
    • その他はすべてそのままにするか、必要に応じてパーソナライズしてください。
  • 生成したら、「CREATE DATABASE」セクションを削除します。 「JiraTemp」を「Jira」に置き換えます。
  • スクリプトを実行します。データベースの構造全体とデータベースの権限が「Jira」に複製されるようになりました。
  • データをコピーする前に、すべての制約を無効にする必要があります。データベース「Jira」で次のコマンドを実行します:EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
  • ここで、データを転送する必要があります。これを行うには、単に「JiraTemp」を右クリックして、「タスク->データのエクスポート...」を選択します。
    • データソースおよび宛先として、SQL Server用のOLE DBプロバイダーを選択します。
    • ソースデータベースは「JiraTemp」です
    • 宛先データベースは「Jira」です
    • サーバー名は、技術的にはソースと宛先で同じです(別のサーバーでデータベースを作成した場合を除く)。
    • 「1つまたは別のテーブルまたはビューからデータをコピーする」を選択します
    • ビューを除くすべてのテーブルを選択します。次に、まだ強調表示されているときに、「マッピングの編集」をクリックします。 [ID挿入を有効にする]をオンにします
    • [OK]、[次へ]、[完了]の順にクリックします
  • データ転送には時間がかかる場合があります。終了したら、次のコマンドを実行して、すべての制約を再度有効にします:exec sp_msforeachtable @command1="print '?'", @command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"

完了したら、JIRAを再起動し、データベースの照合が正常に完了しました。多くの人に役立つことを願っています!

33
David

長さの問題nvarcharを修正し、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

これを行うには、私のために働く簡単な解決策があります。

  1. 新しい照合で新しいデータベースを作成します。
  2. スクリプトモードで元のデータベースのデータをエクスポートします。
  3. スクリプトを使用してコンテンツを新しいデータベースにインポートします(USE文の名前を新しいデータベースに変更します)。

ただし、データベースにトリガーやプロシージャなどがある場合は、データやテーブルだけでなく、注意が必要です。

5
dlopezgonzalez

長さの問題nvarchar(最大値を含む)を修正し、テキストを追加し、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

注意:次のような特定の照合使用条件を変更する必要がある場合:

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

例えばNOT the:AND c.collation_name <> @collate

私の場合、いくつかの列の正しい/指定された照合があり、それらを変更したくありませんでした。

1
Pavlo

次のスクリプトは、(MAX)、IMAGEなどの最新のタイプとともにテーブルスキーマで動作します。この行の必要に応じて照合タイプを変更します(SET @collat​​e = 'DATABASE_DEFAULT';

SQL SCRIPT HERE:

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!'
END
1
Haseeb

PHPMyAdminを使用しているこのソリューションを探している人のために、「操作」タブの下部にオプションがあります(最初にデータベースをクリックします)。 2つのチェックボックス(最初のチェックボックスをオンにすると1つ表示されます):

  • すべてのテーブル照合を変更する
  • すべてのテーブル列の照合順序を変更する

基本的に投稿されたようなスクリプトを実行するようです。コンソールには、実行された最終コマンドが表示されます。

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

私は常に純粋なSQLを好むので:

SELECT 'ALTER TABLE [' + l.schema_n + '].[' 
       + l.table_name + '] ALTER COLUMN [' 
       + l.column_name + '] ' + l.data_type + '(' 
       + Cast(l.new_max_length AS NVARCHAR(100)) 
       + ') COLLATE ' + l.dest_collation_name + ';', 
       l.schema_n, 
       l.table_name, 
       l.column_name, 
       l.data_type, 
       l.max_length, 
       l.collation_name 
FROM   (SELECT Row_number() 
                 OVER ( 
                   ORDER BY c.column_id) AS row_id, 
               Schema_name(o.schema_id)  schema_n, 
               ta.NAME                   table_name, 
               c.NAME                    column_name, 
               t.NAME                    data_type, 
               c.max_length, 
               CASE 
                 WHEN c.max_length = -1 
                       OR ( c.max_length > 4000 ) THEN 4000 
                 ELSE c.max_length 
               END                       new_max_length, 
               c.column_id, 
               c.collation_name, 
               'French_CI_AS'            dest_collation_name 
        FROM   sys.columns c 
               INNER JOIN sys.tables ta 
                       ON c.object_id = ta.object_id 
               INNER JOIN sys.objects o 
                       ON c.object_id = o.object_id 
               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  1 = 1 
               AND c.collation_name = 'SQL_Latin1_General_CP1_CI_AS' 
       --'French_CI_AS'-- ALTER DONE YET OLD VALUE :'SQL_Latin1_General_CP1_CI_AS' 
       ) l 
ORDER  BY l.column_id;
0
David BRU