修改表主键字段数据类型(up_ModifyPrimaryColumn)

开始:

有一需求,就是把表中作为主键字段的数据类型从int 转换为 uniqueidentifier。我们可能会想到直接通过Microsoft SQL Server Management Studio (MSSMS)修改表结构,删除原来的主键,增加一个数据类型为uniqueidentifier的字段作为主键,并对它设置not null default(newid()) 。

对于单独的表,主键没有被其他表作为外键,可以这样修改,但一旦存在外键时,我们就不能这样修改了。至少我们需要通过编写T-SQL语句来实现,基本方法是:

1.删除外键约束

2.修改表字段类型(删除主键约束-->新增uniqueidentifier类型的字段(default(newid())),并设置为主键)

3.在其他表(原主键字段,在其他表作为外键的表)新增uniqueidentifier类型的字段(default(newid()))。

4.更新数据

5.字段重新命名

6.重新创建外键

当然你还要考虑索引是否要重新创建,如果我们要修改一大堆的表,那么需要写一大堆的T-SQl代码。

为了解决这一问题,这里我为此特别写了一个存储过程up_ModifyPrimaryColumn来实现表主键数据类型转换。

up_ModifyPrimaryColumn应用范围:

1.作为主键的字段必须是单一字段

2.不考虑分区

 

存储过程up_ModifyPrimaryColumn:

View Code
Use Test
Go
if object_ID('[up_ModifyPrimaryColumn]') is not null
    Drop Procedure [up_ModifyPrimaryColumn]
Go
Create Proc up_ModifyPrimaryColumn
(
    @objectname sysname=null,
    @columnname sysname=null,
    @type_new sysname=null
)
As
/*
修改表主键字段数据类型(V2.0) Andy 2012-12-8 

说明:在原版脚本的基础上,不删除原表,以确保原来的数据可日后还原。

 
*/
    Set Nocount On
    Declare    @objectid int,
            @columnid int,
            @type_old nvarchar(512),
            @typeid_old int,
            @typeid_new int,
            @Enter nvarchar(10),
            @Tab nvarchar(10),
            @Spacebar nvarchar(10),
            @Date nvarchar(8)
 
    Select    @Enter=Char(13)+Char(10),
            @Tab=Char(9),
            @Spacebar=Char(32),
            @Date=Convert(char(8),Getdate(),112)
 
    Select @objectid=object_id,@objectname=name
        From sys.objects As a
        Where name=@objectname And type='U' And is_ms_shipped=0 And
        Not Exists(Select 1 
                        From sys.extended_properties 
                        Where major_id=a.Object_id 
                            And minor_id=0 
                            And class=1 
                            And Name = N'microsoft_database_tools_support'
                    )
 
    If @objectid Is null
    Begin
        Raiserror 50001 N'无效的表名!'
        Return 
    End
    
    If not Exists(Select 1 From sys.columns Where object_id=@objectid And name=@columnname)
    Begin
        Raiserror 50001 N'无效的字段名!'
        Return
    End
    
    If Not Exists(Select 1 
                    From sys.indexes As a  
                        Inner Join sys.index_columns As b On b.object_id=a.object_id 
                            And b.index_id=a.index_id  
                            And b.index_id=1  
                            And a.is_primary_key=1
                        Inner Join sys.columns As c On c.object_id=b.object_id 
                            And c.column_id=b.column_id
                    Where a.object_id=@objectid  
                            And c.name=@columnname
                 )
    Begin
        Raiserror 50001 N'非主键字段,不需要调用当前存储过程来修改数据类型.'
        Return
    End

    
    Exec('Declare @x '+@type_new)
    If @@Error>0
    Begin
        Print N'数据类型定义错误!'
        Return
    End
 
    Set @typeid_new=type_id(Left(@type_new+'(',Charindex('(',@type_new+'(')-1))
 
    If Object_id('tempdb..#ScriptTable') Is Not null
        Drop Table #ScriptTable
    Create Table #ScriptTable (id int Identity(1,1) Primary Key,[content] nvarchar(4000))
 
    /* 1. Drop Constraint and Index */
 
    If Object_id('tempdb..#Tables') Is Not null
        Drop Table #Tables
    Create Table #Tables
    (
        objectid int Primary Key,
        objectname sysname,
        columnid int ,
        columnname sysname,
        typeid_new int,
        type sysname,
        TypeDefinition_new nvarchar(512),
        Flag bit,
        IsIdentity_new bit,
        IsRowGuidCol_new bit
    )
    
    Insert Into #Tables
        Select    a.object_id,object_name(a.object_id),a.column_id,a.name,a.user_type_id,b.name,
                @type_new +
                    Case 
                        When @typeid_new In(48,52,56,59,62,106,108,127) And a.object_id=@objectid Then ' Not null Identity(1,1)'
                        When @typeid_new =36 And a.object_id=@objectid Then ' Rowguidcol Not null '
                        Else ''
                    End, 
                Case a.object_id When @objectid Then 1 Else 0 End,
                Case When @typeid_new In(48,52,56,59,62,106,108,127) Then 1 Else 0 End,
                Case When @typeid_new =36 Then 1 Else 0 End
            From sys.columns As a
                Inner Join sys.types As b On b.user_type_id=a.user_type_id
            Where (a.object_id=@objectid And a.name=@columnname) Or 
                    Exists    (Select 1 
                                From sys.foreign_key_columns 
                                Where parent_object_id=a.object_id  And
                                        Referenced_object_id=@objectid And parent_column_id=a.column_id
                            )
 
    Insert Into #ScriptTable
        Select 'Use '+Quotename(db_name())+@Enter+'Go'
 
    Insert Into #ScriptTable
    Select 'If object_id('''+Quotename(a.name)+''') Is Not Null Alter Table '+
            Quotename(object_name(a.parent_object_id))+' Drop Constraint '+Quotename(a.name)+@Enter+'Go'
        From sys.objects As a
            Left Outer Join #Tables As b On b.objectid=a.Parent_object_id
        Where a.type In('PK','F ','D ','C ','UQ') And 
                (    Exists(Select 1 From #Tables Where objectid=a.Parent_object_id) Or 
                    Exists(Select 1 
                                From sys.foreign_keys as x 
                                    Inner Join #Tables As y On y.objectid=x.referenced_object_id 
                                        And x.object_id=a.object_id
                          )
                )
        Order By b.Flag ,
            Case a.type 
                    When 'D ' Then 1 
                    When 'C ' Then 2
                    When 'UQ' Then 3
                    When 'F ' Then 4
                    When 'PK' Then 5
                    Else 6 
                End
    
        

    Insert Into #ScriptTable
    Select 'If Exists(Select 1 From sys.indexes Where object_id=object_id('''+b.objectname+''') And name='''+
            a.name+''') Drop Index '+Quotename(b.objectname)+'.'+
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值