2009-04-12 75 views
10

所以我有一个旧的数据库,我正在迁移到一个新的。新的有一个略有不同,但大多数兼容的模式。另外,我想重新编号从零开始的所有表格。TSQL:更新与插入选择从

目前我一直在使用我写的手动检索旧记录的工具,将它插入到新数据库中,并更新旧数据库中的v2 ID字段以在新数据库中显示其相应的ID位置。

例如,我从MV5.Posts中选择并插入到MV6.Posts中。插入后,我检索MV6.Posts中新行的ID,并在旧MV5.Posts.MV6ID字段中更新它。

有没有办法做到这一点更新通过INSERT INTO SELECT FROM,所以我不必手动处理每个记录?我正在使用SQL Server 2005,开发版。

回答

9

与迁移的关键是做几件事情:一是 ,没有做任何事情没有最新的备份。 其次,如果密钥将会改变,您需要至少暂时在新结构中存储旧的和新的(永久性地如果密钥字段暴露给用户,因为它们可能正在搜索它以获取旧记录)。

接下来,您需要深入了解与子表的关系。如果您更改关键字段,则所有相关表格也必须更改。这是存储新旧密钥的地方。如果您忘记更改其中的任何一项,数据将不再正确,并且将无用。所以这是关键的一步。

挑出一些特别复杂数据的测试用例,确保为每个相关表格包含一个或多个测试用例。将现有值存储在工作表中。

要开始迁移,请使用旧表中的选择插入到新表中。根据记录数量的不同,您可能希望循环执行批处理(一次不记录一条记录)以提高性能。如果新密钥是标识,只需将旧密钥的值放入其字段中,并让数据库创建新密钥。

然后对相关表格做同样的处理。然后,使用旧的键值在表中的东西,如更新外键字段:

Update t2 
set fkfield = newkey 
from table2 t2 
join table1 t1 on t1.oldkey = t2.fkfield 

测试您的迁移与您在迁移前存储什么运行测试用例和比较数据。彻底测试迁移数据或者无法确定数据是否与旧结构一致是非常关键的。移民是一项非常复杂的行动;花费你的时间并且非常有条理和彻底地完成它是值得的。

0

AFAIK,你不能更新一个SQL语句

但是,您可以使用触发器来实现你想做的事两个不同的表。

2

我知道的最好的办法是与output clause。假设你有SQL 2005或2008.

USE AdventureWorks; 
GO 
DECLARE @MyTableVar table(ScrapReasonID smallint, 
          Name varchar(50), 
          ModifiedDate datetime); 
INSERT Production.ScrapReason 
    OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate 
     INTO @MyTableVar 
VALUES (N'Operator error', GETDATE()); 

它仍然需要第二遍更新原始表;不过,它可能会使你的逻辑更简单。你需要更新源表吗?您可以将新的ID存储在第三个交叉引用表中。

1

heh。我记得在迁移中这样做。

将old_id放入新表中使得更新变得更容易 - 您可以仅执行一次insert into newtable select ... from oldtable,以及后续的“拼接”记录。在“针”中,您将通过在新父项(insert into newchild select ... (select id from new_parent where old_id = oldchild.fk) as fk, ... from oldchild)上执行子选择来更新子插入表中的子表的外键,否则您将插入子项并执行单独更新以修复外键。

在一个插入中做它会更快;在单独的步骤中进行测量,以确定您的插入不依赖于顺序,并且可以在必要时重新进行。

迁移后,您可以删除old_id列,或者,如果您有遗留系统公开系统ID并且用户使用这些密钥作为数据的情况,则可以保留它们以允许使用基于old_id。

事实上,如果您正确定义了外键,则可以使用systables/information-schema来生成插入语句。

4

可能最简单的方法是在MVI上为oldId添加一列,然后将旧表中的所有记录插入到新表中。

UPDATE mv5.posts 
SET newid = n.id 
FROM mv5.posts o, mv6.posts n 
WHERE o.id = n.oldid 

你可以清理,之后删除OLDID列,如果你想:最后,用类似更新在新表上OLDID旧表匹配。

+0

我实际上认为把oldId留在新表上比在旧表上使用newId更好,这使得它更容易。 – ninesided 2009-04-13 01:11:04

0

在MV6.Post.OldMV5Id

做出 INSERT INTO MV6.Post 选择使列..从MV5.Post

然后作出MV5.Post的更新。MV6ID

1

有没有办法通过INSERT INTO SELECT做到这一点的更新不这样我就不必手动处理每一条记录?

既然你不想做手动,但自动,在MV6.Posts创建一个触发器,这样,当你插入MV6.Posts发生UPDATEMV5.Posts自动。

而且你的触发可能看起来像,

create trigger trg_MV6Posts 
on MV6.Posts 
after insert 
as 
begin 
    set identity_insert MV5.Posts on 

    update MV5.Posts 
    set ID = I.ID 
    from inserted I 

    set identity_insert MV5.Posts off 
end