74

我导入了一个包含一些数据的数据库以与另一个数据库进行比较。

目标数据库有排序规则Latin1_General_CI_AS,源数据库有SQL_Latin1_General_CP1_CI_AS.

我确实将源数据库的排序规则更改为Latin1_General_CI_AS使用 SQL Server Management Studio。但是里面的表格和列仍然使用旧的排序规则。

我知道我可以使用以下方法更改列:

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

但我必须对里面的所有表和所有列执行此操作。

在我知道之前开始编写一个存储过程,它读取所有表和所有类型的列,varchar并在表和列游标循环中更改它们......

有谁知道一种更简单的方法,或者是唯一的方法是通过一个脚本在一个过程中运行所有表来做到这一点?

4

12 回答 12

81

由于我没有找到合适的方法,所以我编写了一个脚本来完成它,我在这里为需要它的人分享它。该脚本遍历所有用户表并收集列。如果列类型是任何 char 类型,则它会尝试将其转换为给定的排序规则。

列必须是无索引和无约束的才能工作。

如果有人对此仍有更好的解决方案,请发布!

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
于 2013-08-08T10:16:35.270 回答
40

所以在这里,我再次对答案不满意。我的任务是将 JIRA 6.4.x 升级到 JIRA Software 7.x,并且我解决了数据库和列排序规则的特定问题。

在 SQL Server 中,如果您不删除诸如主键或外键甚至索引之类的约束,则上面提供的作为答案的脚本根本不起作用。然而,它会改变那些没有这些属性的人。这确实有问题,因为我不想手动删除所有约束并重新创建它们。该操作可能以错误告终。另一方面,创建自动化更改的脚本可能需要很长时间才能完成。

所以我找到了一种方法来简单地使用 SQL Management Studio 进行迁移。这是程序:

  • 用别的东西重命名数据库。例如,我的是“Jira”,所以我将其重命名为“JiraTemp”。
  • 创建一个名为“Jira”的新数据库并确保设置正确的排序规则。只需选择页面“选项”并更改排序规则。
  • 创建后,返回“JiraTemp”,右键单击它,“Tasks -> Generate Scripts...”。
    • 选择“编写整个数据库和所有数据库对象的脚本”。
    • 选择“保存到新的查询窗口”,然后选择“高级”
    • 将“服务器版本脚本”的值更改为所需的值
    • 启用“脚本对象级权限”、“脚本所有者”和“脚本全文索引”
    • 如果您愿意,可以保留其他所有内容或对其进行个性化设置。
  • 生成后,删除“CREATE DATABASE”部分。将“JiraTemp”替换为“Jira”。
  • 运行脚本。数据库的整个数据库结构和权限现在已复制到“Jira”。
  • 在我们复制数据之前,我们需要禁用所有约束。在数据库“Jira”中执行以下命令:EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
  • 现在需要传输数据。为此,只需右键单击“JiraTemp”,然后选择“任务 -> 导出数据...”
    • 选择 SQL Server 的 OLE DB 提供程序作为数据源和目标。
    • 源数据库是“JiraTemp”
    • 目标数据库是“Jira”
    • 源和目标的服务器名称在技术上是相同的(除非您在另一台服务器上创建了数据库)。
    • 选择“从一个或另一个表或视图复制数据”
    • 选择除视图之外的所有表。然后,当仍然突出显示时,单击“编辑映射”。选中“启用身份插入”
    • 单击确定,下一步,然后完成
  • 数据传输可能需要一段时间。完成后,执行以下命令以重新启用所有约束:exec sp_msforeachtable @command1="print '?'", @command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"

完成后,我重新启动了 JIRA,并且我的数据库排序规则正常。希望对很多人有帮助!

于 2016-02-03T15:02:30.140 回答
17

修复长度问题 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
于 2014-01-31T10:55:41.827 回答
5

为此,我有一个适合我的简单解决方案。

  1. 使用新排序规则创建一个新数据库。
  2. 以脚本方式导出原始数据库的数据。
  3. 使用脚本将内容导入新数据库(将 USE 语句重命名为新数据库)。

但是,如果您的数据库有触发器、过程或类似的东西——不仅仅是数据和表,您需要谨慎行事。

于 2015-02-15T21:08:14.630 回答
5

我对剧本做了一点改动。

DECLARE @collate nvarchar(100);
DECLARE @table sysname;
DECLARE @schema sysname;
DECLARE @objectId int;
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 tbl.TABLE_SCHEMA,[name],obj.id
FROM sysobjects as obj
inner join INFORMATION_SCHEMA.TABLES as tbl
on obj.name = tbl.TABLE_NAME
WHERE OBJECTPROPERTY(obj.id, N'IsUserTable') = 1

OPEN local_table_cursor
FETCH NEXT FROM local_table_cursor
INTO @schema, @table, @objectId;

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 = @objectId
    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 ' + @schema + '.' + @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 @schema,@table,@objectId

END

CLOSE local_table_cursor
DEALLOCATE local_table_cursor

GO
于 2020-05-26T19:07:15.993 回答
3

固定长度问题 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'

例如不是AND c.collation_name <> @collate

就我而言,我对某些列进行了正确/指定的排序规则,并且不想更改它们。

于 2017-02-21T12:07:05.267 回答
2

很抱歉聚会迟到了,但这是我的 - 为带有模式和有趣的列和表名的表提供服务。是的,我有一些。

SELECT 
    'ALTER TABLE [' +  TABLE_SCHEMA + '].[' + TABLE_NAME  
    + '] ALTER COLUMN [' + COLUMN_NAME + '] ' + DATA_TYPE 
    + '(' + CAST(CHARACTER_MAXIMUM_LENGTH AS nvarchar(100)) 
    + ') COLLATE ' + 'Latin1_General_CI_AS' 
    + CASE WHEN IS_NULLABLE = 'YES' THEN ' NULL' ELSE ' NOT NULL' END 
FROM 
    INFORMATION_SCHEMA.COLUMNS 
WHERE 
    DATA_TYPE like '%char'
于 2018-05-22T15:35:52.900 回答
1

以下脚本将与表模式以及 (MAX)、IMAGE 等最新类型一起使用。根据您在此行上的需要更改排序规则类型 ( SET @collat​​e = 'DATABASE_DEFAULT'; )

此处的 SQL 脚本:

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
于 2018-11-19T14:27:02.977 回答
0

我总是喜欢纯 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;
于 2019-03-14T23:34:59.570 回答
0

使用上面基于游标的变体作为起点,下面的脚本只会输出一组 UPDATE 语句以设置为 DATABASE_DEFAULT,它实际上不会执行 UPDATES

它支持模式、完整的字符和文本类型集,并保留现有的 NULL / NOT NULL。

我计划使用输出来查找在较低环境中失败的语句,然后手动调整生成的脚本以根据需要删除和重新创建约束。

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 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 = 'DATABASE_DEFAULT';

DECLARE local_table_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
ORDER BY s.[name], o.[name]

OPEN local_table_cursor FETCH NEXT FROM local_table_cursor INTO @schema,@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(@schema+'.'+@table) AND (t.Name LIKE '%char%' OR t.Name LIKE '%text%') 
    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'

        SET @sql =
        CASE 
            WHEN @data_type like '%text%' 
            THEN 'ALTER TABLE [' + @schema+ '].['+ @table + '] ALTER COLUMN [' + @column_name + '] ' + @data_type + ' COLLATE ' + @collate + ' ' + CASE WHEN @is_nullable = 0 THEN 'NOT NULL' ELSE 'NULL' END
            ELSE 'ALTER TABLE [' + @schema+ '].['+ @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

        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 @schema, @table
END

CLOSE local_table_cursor
DEALLOCATE local_table_cursor
GO
于 2020-12-04T05:46:04.590 回答
0

更改包括所有字段的数据库的排序规则的最简单方法是合并复制:

  • 使用具有目标排序规则的服务器(服务器排序规则道具)
  • 在旧服务器上创建合并发布
  • 将源数据库的所有产品添加到发布中
  • 运行 snapsoht 代理并等待它完成
  • 将推送订阅添加到您的出版物,并使用漂亮的排序规则定位服务器
  • 初始化订阅
  • 签入复制监视器并等待代理准备好
  • 删除订阅
  • 删除出版物

以下sql scipt为您的用户表创建合并发布我在 Managemet Studio 中执行的其他步骤,以及在后续步骤中使用单独的脚本创建脚本对象,如存储过程、视图等。

ALTER PROCEDURE [dbo].[CreateMergePublication]
    @PublicationName nvarchar(max) = N'Pubi'
AS BEGIN
SET NOCOUNT ON
    BEGIN TRY


        -- *** BEGIN BLL ***


        declare @DBName nvarchar(max) 
        select top 1 @DBName = TABLE_CATALOG from INFORMATION_SCHEMA.TABLES
        exec sp_replicationdboption @dbname = @DBName, @optname = N'merge publish', @value = N'true'

        -- Mergeveröffentlichung wird hinzugefügt
        declare @desc nvarchar(max) = N'Mergeveröffentlichung der ' + @dbname + '-Datenbank von Verleger ' + @@SERVERNAME
        exec sp_addmergepublication 
            @publication = @PublicationName, 
            @description = @desc , 
            @sync_mode = N'native', 
            @retention = 14, 
            @allow_push = N'true', 
            @allow_pull = N'true', 
            @allow_anonymous = N'true', 
            @enabled_for_internet = N'false', 
            @snapshot_in_defaultfolder = N'true', 
            @compress_snapshot = N'false', 
            @ftp_port = 21, 
            @ftp_subdirectory = N'ftp', 
            @ftp_login = N'anonymous', 
            @allow_subscription_copy = N'false', 
            @add_to_active_directory = N'false', 
            @dynamic_filters = N'false', 
            @conflict_retention = 14, 
            @keep_partition_changes = N'false', 
            @allow_synctoalternate = N'false', 
            @max_concurrent_merge = 0, 
            @max_concurrent_dynamic_snapshots = 0, 
            @use_partition_groups = null, 
            @publication_compatibility_level = N'100RTM', 
            @replicate_ddl = 1, 
            @allow_subscriber_initiated_snapshot = N'false', 
            @allow_web_synchronization = N'false', 
            @allow_partition_realignment = N'true', 
            @retention_period_unit = N'days', 
            @conflict_logging = N'both', 
            @automatic_reinitialization_policy = 0


        exec sp_addpublication_snapshot 
            @publication = @PublicationName, 
            @frequency_type = 4, 
            @frequency_interval = 14, 
            @frequency_relative_interval = 1, 
            @frequency_recurrence_factor = 0, 
            @frequency_subday = 1, 
            @frequency_subday_interval = 5, 
            @active_start_time_of_day = 500, 
            @active_end_time_of_day = 235959, 
            @active_start_date = 0, 
            @active_end_date = 0, 
            @job_login = null, 
            @job_password = null, 
            @publisher_security_mode = 1

        declare @schema nvarchar(max), @table nvarchar(max), @uniquename nvarchar(max)
        declare cr cursor for
            select TABLE_SCHEMA, TABLE_NAME from INFORMATION_SCHEMA.TABLES 
            where TABLE_TYPE = 'BASE TABLE' and TABLE_NAME not like 'sys%' and TABLE_NAME not like 'ms%' and TABLE_NAME not like 'dtprop%'
            order by TABLE_NAME
        open cr
        WHILE 1=1 BEGIN
            FETCH cr INTO @schema, @table
            IF @@FETCH_STATUS <> 0 BREAK
            set @uniquename = @schema + @table

            print @schema + '.' + @table + ' (' + @uniquename + ')'
            exec sp_addmergearticle 
                @publication = @PublicationName, 
                @article = @uniquename, 
                @source_owner = @schema, 
                @source_object = @table, 
                @type = N'table', 
                @description = N'', 
                @creation_script = null, 
                @pre_creation_cmd = N'none', 
                @schema_option = 0x000000010C034FD1, 
                @identityrangemanagementoption = N'manual', 
                @destination_owner = @schema, 
                @force_reinit_subscription = 1, 
                @column_tracking = N'false', 
                @subset_filterclause = N'', 
                @vertical_partition = N'false', 
                @verify_resolver_signature = 1, 
                @allow_interactive_resolver = N'false', 
                @fast_multicol_updateproc = N'true', 
                @check_permissions = 0, 
                @subscriber_upload_options = 0, 
                @delete_tracking = N'true', 
                @compensate_for_errors = N'false', 
                @stream_blob_columns = N'false', 
                @partition_options = 0

        END 

        close cr
        deallocate cr





        -- *** END BLL ***

    END TRY
    BEGIN CATCH
        IF CURSOR_STATUS('global','cr') >= 0
        BEGIN 
            close cr
            deallocate cr
        END

        DECLARE @ErrMsg nvarchar(4000), @ErrSeverity INT, @ErrorState INT;
        SELECT @ErrMsg = ERROR_MESSAGE(),@ErrSeverity = ERROR_SEVERITY(),@ErrorState = ERROR_STATE()
        RAISERROR(@ErrMsg, @ErrSeverity, @ErrorState)


    END CATCH;

END
于 2021-07-27T19:13:52.427 回答
0

这个答案可能有点晚,但您也可以生成语句。这将比使用 CURSOR 快得多。

select 
'ALTER TABLE '+ tb.TABLE_NAME + ' ALTER COLUMN '+ cl.COLUMN_NAME + ' ' + DATA_TYPE +'('+ cast(CHARACTER_MAXIMUM_LENGTH as nchar(3)) + ') ' + 'COLLATE Latin1_General_CI_AS '
FROM [DATABASE].INFORMATION_SCHEMA.columns cl  
left join [DATABASE].tables tb on tb.TABLE_NAME = cl.TABLE_NAME and tb.Table_Schema=cl.table_schema 
left join  [DATABASE].INFORMATION_SCHEMA.KEY_COLUMN_USAGE kc on kc.table_name = tb.table_name and kc.TABLE_SCHEMA = cl.TABLE_SCHEMA  and kc.column_name=cl.COLUMN_NAME
WHERE DATA_TYPE in ('nvarchar','nchar')

希望这可以帮助某人。

于 2021-10-18T16:18:38.007 回答