【问题标题】:Change type of a column with numbers from varchar to int将带有数字的列的类型从 varchar 更改为 int
【发布时间】:2009-02-23 13:58:03
【问题描述】:

我们在当前类型为 varchar(16) 的数据库中有两列。问题是,它包含数字并且总是包含数字。因此,我们希望将其类型更改为整数。但问题是它当然已经包含数据。

有什么方法可以将该列的类型从 varchar 更改为 int,而不会丢失所有已经存在的数字?希望我们可以运行某种 sql,而不必创建临时列并创建 C# 程序或其他东西来进行转换等等......我想如果 SQL Server 有一些函数可以将字符串转换为数字,但我在 SQL 上非常不稳定。几乎只能使用 C# 并通过 LINQ to SQL 访问数据库。

注意:是的,首先将列设为 varchar 并不是一个好主意,但不幸的是,他们就是这样做的。

【问题讨论】:

    标签: sql-server types


    【解决方案1】:

    唯一可靠的方法是使用临时表,但不会使用太多 SQL:

    select * into #tmp from bad_table
    truncate table bad_table
    alter bad_table alter column silly_column int
    insert bad_table
    select cast(silly_column as int), other_columns
    from #tmp
    drop table #tmp
    

    【讨论】:

    • #tmp 是 tmp 表的随机名称?
    • 好的答案 - 我会先运行这个 - 从 bad_table 中选择 cast(silly_column as int), other_columns 以确保您没有任何转换问题,它们实际上都是整数。
    • 哈哈,不,不,我想知道 # 字符是否是使它成为临时表的原因。或者它只是任何不存在的名称,或者它是如何工作的......
    • 单个 # 表示特定于连接的临时表(仅在该连接中可用),而双哈希 ## 表示全局临时表(所有连接均可访问)
    • sigh 由于外键约束,截断不起作用。我可以在弄乱它时以某种方式禁用它,然后再将其重新打开吗?
    【解决方案2】:

    最简单的方法是:

    alter table myTable alter column vColumn int;
    

    只要

    1. 所有数据都适合 int 格式
    2. 所有数据都可以转换为 int(即“car”的值将失败)
    3. 没有包含 vColumn 的索引。如果有索引,您将需要添加一个 drop 并创建它们以使它们回到原来的位置。

    【讨论】:

    • @svish:我真的希望它是“汽车”而不是“字符”。
    • 哦!对不起。现在明白你的意思了,嘿嘿:)
    • 这很奏效。尝试通过管理工作室时失败
    • @jmoreno 有什么办法可以用order by LENGTH(col) 更改或更新表???
    • @AshishKamble:这必须是一个单独的问题,更多的细节解释你想要什么。
    【解决方案3】:

    只需在 SQL Server Management Studio 中更改数据类型。

    (您可能需要转到菜单 ToolsOptionsDesigners,并禁用阻止保存重新创建的更改的选项表。)

    【讨论】:

    • 那我不会失去所有的价值吗??
    • 没有。如果你愿意,可以在测试台上试试?
    • 我刚刚完成了这项工作,效果很好。首先,我检查了所有现有值是否都是以字符串类型存储的数字,以及我是否可以成功地将所有 varchars 转换为数字类型。在我禁用对列(索引、键、触发器等)的所有引用并继续应用 MSSMS 中的更改之后。太好了!
    • 这对我来说失败了,但上面的 alter table 语句有效
    • 在设计菜单中的 SSMS 中执行 对于大表 可能会预先警告您:Saving Definition Changes to tables with large amounts of data could take a considerable amount of time. While changes are being saved, table data will not be accessible.,或者可能会失败:- Unable to modify table. Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.,除非您更改 Tools → Options → Designers选项“覆盖表设计器更新的连接字符串超时”。我也认为ALTER TABLE 声明对我来说可能更好。
    【解决方案4】:

    我非常感谢以前的答案,但也认为更完整的答案会对其他搜索者有所帮助...

    如果您在生产类型表上进行更改,有几个注意事项会有所帮助。

    1. 如果您在表上定义了 identity 列,则必须在重新插入数据时将IDENTITY_INSERT 设置为打开和关闭。您还必须使用明确的列列表。
    2. 如果您想确保不会杀死数据库中的数据,请在 truncate/alter/reinsert 过程周围使用TRANSACTIONS
    3. 如果您有大量数据,则尝试仅在 SQ Server Management Studio 中进行更改可能会因超时而失败,并且您可能会丢失数据。

    要扩展@cjk 给出的答案,请查看以下内容:

    注意:'tuc' 只是此脚本中真实表名的占位符

    begin try 
      begin transaction
    
      print 'Selecting Data...'
      select * into #tmp_tuc from tuc
    
      print 'Truncating Table...'
      truncate table tuc
    
      alter table tuc alter column {someColumnName} {someDataType} [not null]
      ... Repeat above until done
    
      print 'Reinserting data...'
      set identity_insert tuc on
      insert tuc (
        <Explicit column list (all columns in table)>
      )
      select  
        <Explicit column list (all columns in table - same order as above)>
      from #tmp_tuc
      set identity_insert tuc off
    
      drop table #tmp_tuc
      commit
      print 'Successful!'
    end try
    begin catch
      print 'Error - Rollback'
      if @@trancount > 0
        rollback
    
      declare @ErrMsg nvarchar(4000), @ErrSeverity int
      select @ErrMsg = ERROR_MESSAGE(), @ErrSeverity = ERROR_SEVERITY()
    
      set identity_insert tuc off
    
      RAISERROR(@ErrMsg, @ErrSeverity, 1)
    end catch
    

    【讨论】:

      猜你喜欢
      • 2018-12-31
      • 1970-01-01
      • 1970-01-01
      • 2017-04-05
      • 2018-04-14
      • 1970-01-01
      • 2013-11-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多