TSQL:使用INSERT INTO SELECT FROM更新

时间:2009-04-12 22:23:30

标签: c# sql tsql migration bulkinsert

所以我有一个旧的数据库,我正在迁移到一个新的数据库。新的架构略有不同但大部分兼容。另外,我想从零重新编号所有表。

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

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

有没有办法通过INSERT INTO SELECT FROM执行此UPDATE所以我不必手动处理每个记录?我正在使用SQL Server 2005,开发版。

7 个答案:

答案 0 :(得分:10)

迁移的关键是做几件事: 首先,如果没有当前备份,请不要执行任何操作。 其次,如果密钥将发生变化,则需要至少暂时将新旧结构存储在新结构中(永久性地,如果密钥字段向用户公开,因为他们可能正在搜索它以获取旧记录)。

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

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

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

然后对相关表格执行相同操作。然后使用表中的旧键值来更新外键字段,如:

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

通过运行测试用例并将数据与迁移前存储的数据进行比较来测试迁移。彻底测试迁移数据至关重要,或者您无法确定数据是否与旧结构一致。迁移是一项非常复杂的行动;花时间去做非常有条不紊和彻底的工作是值得的。

答案 1 :(得分:5)

可能最简单的方法是在oldId的MV6.Posts上添加一列,然后将旧表中的所有记录插入到新表中。最后,在新表中更新旧表匹配的oldId,如下所示:

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

如果您愿意,可以随后清理并删除oldId列。

答案 2 :(得分:3)

我所知道的最好的就是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存储在第三个交叉引用表中。

答案 3 :(得分:2)

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

将old_id放在新表中会使更新变得更容易 - 您可以只执行insert into newtable select ... from oldtable, - 然后更容易记录随后的“拼接”。在“stitch”中,您将通过在新父级(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 :(得分:2)

  

有没有办法通过INSERT INTO SELECT FROM执行此UPDATE所以我不必手动处理每条记录?

由于您不想手动手动,但 自动 ,请在MV6.Posts上创建触发器,以便{当您插入UPDATE时,MV5.Posts会自动{1}}。

你的触发器可能看起来像,

MV6.Posts

答案 5 :(得分:1)

AFAIK,您无法使用单个sql语句更新两个不同的表

但是,您可以使用触发器来实现您想要的目标。

答案 6 :(得分:1)

在MV6.Post.OldMV5Id

中创建一个列

制作一个 插入MV6.Post 从MV5.Post

中选择..

然后更新MV5.Post.MV6ID