代码之家  ›  专栏  ›  技术社区  ›  Andy Joiner

数据丢失警告在表中间添加列

  •  4
  • Andy Joiner  · 技术社区  · 11 年前

    新列已添加到表中,但新列并没有添加到表定义的末尾(最右边的列),而是添加到表的中间。

    Table differences

    当我试图在Redgate SQL源代码管理中提交时,我会收到警告“这些更改可能会导致数据丢失”

    • 数据丢失真的会发生吗?
    • 是否有办法预览更改脚本以确认不会丢失任何数据?
      • 我可以复制脚本并轻松地将其转换为Migrations V2脚本吗?
    • 我必须这样做吗
      • 在SSMS中编辑表格,并将新列移到末尾
      • 还是编写迁移脚本?
    • 如果是的话,有什么方便的工具可以做重复的事情吗?
    3 回复  |  直到 11 年前
        1
  •  5
  •   Jon    11 年前

    我为Red Gate的SQL源代码管理工作。

    这种改变需要重新创建一个表。默认情况下,SSMS不允许您保存更改。但是,该选项必须已在SSMS中禁用。它位于“工具”下->选项->设计师->表和数据库设计器->防止保存需要重新创建表的更改。

    如果该功能被禁用,SQL源代码管理会将其视为潜在的数据丢失情况,并提示您是否要添加迁移脚本。

    如果您团队中的其他开发人员通过获取最新信息来获取此更改,那么SQL源代码管理将根据其本地数据库的当前状态,向他们提供更多详细信息,以了解任何潜在的数据丢失。如果唯一的更改是向现有表中添加列,则不会删除未更改列中的数据。

    如果您正在部署到另一个数据库(例如staging/UAT/prod),并且您有SQL Compare,那么如果您尝试在另一个非本地数据库上运行它,您可以使用它来查看将应用于数据库的确切内容。选择创建部署脚本选项,就可以在运行之前对SQL进行健全性检查。

    正如您所说,将列添加到表的末尾将避免重新生成的需要,因此如果您不需要担心列在哪里,这可能是避免这种情况的最简单方法。

    或者,您可以将迁移脚本添加到:

    1. 使用临时名称创建具有新结构的新表
    2. 将现有数据复制到临时表
    3. 删除现有表
    4. 将新临时表重命名为原始名称

    您提到了Migrations v2,这是一个测试版功能,它改变了迁移的工作方式,以便更好地支持分支和合并以及DVCS系统。看见 http://www.red-gate.com/migrations

    版本1迁移脚本需要进行一些修改才能转换为v2迁移脚本。这是一个相当微不足道的变化。我们目前正在记录这一变化,如果您想了解更多关于这一变化的信息,请联系我们的谷歌小组。 https://groups.google.com/forum/#!forum/red-gate-migrations

        2
  •  1
  •   Andy Joiner    11 年前

    我使用SSMS将该列移动到表的末尾,以消除对迁移脚本的需求。

    在类似的场景中,移动列不方便,这就是我将SSMS脚本转换为Migrations V2脚本所做的操作。

    • 撤消SSMS中的更改(删除该列)
    • 在SSMS中恢复更改,但我没有将更改直接保存到数据库,而是保存了更改脚本
    • 修改了更改脚本
      • 修剪了SSMS事务&环境包装器
      • 添加了一个保护子句:IF COL_LENGTH('MyTable','MyColumn')为NULL
      • 将脚本包装在BEGIN TRAN-ROLLBACK TRAN中,以测试脚本而不污染数据库
      • 将GO替换为END BEGIN
      • 在回滚事务中进行测试
      • 删除了BEGIN TRAN-ROLLBACK TRAN开发包装

    Visual diff of converting SSMS to Redgate

        3
  •  0
  •   Sven Schoenung    8 年前

    下面是一个简单的sql查询,它将有助于在数据库表中插入列而不会丢失数据。

    比方说 CCDetails 是要在其中插入列的表 GlobaleNote 就在列之前 Sys_CreatedBy :

    declare @str1 nvarchar(1000)
    declare @tableName nvarchar(1000)
    set @tableName='CCDetails'
    set @str1 = ''
    SELECT @str1 = @str1 + ', ' + COLUMN_NAME
    FROM Information_Schema.Columns
    WHERE Table_Name = @tableName 
    ORDER BY Ordinal_Position
    set @str1 = right(@str1, len(@str1) - 2)
    set @str1 = 'select ' + @str1 +'  into '+@tableName+'Temp from '+@tableName+' ; Drop Table '+ @tableName + ' ; EXEC sp_rename '+@tableName+'Temp, '+@tableName
    set @str1 = REPLACE(@str1,'Sys_CreatedBy','CAST('''' as nvarchar(max)) As GlobaleNote , Sys_CreatedBy' )
    
    exec sp_executesql @str1