更改SQL Server中所有表的所有列的排序规则

Yve*_*esR 47 sql-server database-design collate

我导入了一个数据库,其中包含一些数据,以便与另一个数

目标数据库具有排序规则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
Run Code Online (Sandbox Code Playgroud)

但是我必须为所有表和内部的所有列执行此操作.

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

有没有人知道一个更简单的方法,或者是通过运行程序中所有表的脚本执行此操作的唯一方法?

Yve*_*esR 57

由于我没有找到一个正确的方法,我写了一个脚本来做它,我在这里为那些需要它的人分享它.该脚本将遍历所有用户表并收集列.如果列类型是任何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
Run Code Online (Sandbox Code Playgroud)

  • 如果使用模式,则应将选择[名称]从sysobjects链接到:SELECT sys.schemas.name +'.' + sys.objects.name AS名称FROM sys.objects INNER JOIN sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id WHERE type_desc ='USER_TABLE' (2认同)

Dav*_*vid 33

所以我再次对答案不满意.我的任务是将JIRA 6.4.x升级到JIRA Software 7.x,我在数据库和列整理方面遇到了这个特殊问题.

在SQL Server中,如果不删除主键或外键甚至索引等约束,则上面提供的脚本作为答案根本不起作用.然而,它会改变那些没有这些属性的人.这确实有问题,因为我不想手动删除所有约束并将其创建回来.该操作可能最终会出错.另一方面,创建一个自动化更改的脚本可能需要很长时间.

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

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

完成后,我重新启动了JIRA,我的数据库整理正常.希望它能帮助很多人!


小智 15

固定长度问题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
Run Code Online (Sandbox Code Playgroud)


小智 7

我对剧本做了一点改动。

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
Run Code Online (Sandbox Code Playgroud)

  • 你能说出你做了哪些改变吗?不管怎样,我已经成功地使用了你的脚本。所以谢谢你。 (3认同)

dlo*_*lez 5

要做到这一点,我有一个适合我的简单解决方案.

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

但是,如果您的数据库有触发器,过程或类似的东西,您需要谨慎 - 更多的只是数据和表.