11

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

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

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

有没有办法通过 INSERT INTO SELECT FROM 进行此更新,这样我就不必手动处理每条记录?我正在使用 SQL Server 2005,开发版。

4

7 回答 7

10

迁移的关键是做几件事:首先,不要在没有当前备份的情况下做任何事情。其次,如果键将发生变化,您需要至少暂时将旧的和新的存储在新结构中(如果键字段永久暴露给用户,因为他们可能正在通过它进行搜索以获取旧记录)。

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

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

要开始迁移,请使用从旧表中选择插入到新表中。根据记录的数量,您可能希望循环遍历批次(一次不是一条记录)以提高性能。如果新键是一个身份,您只需将旧键的值放在其字段中,让数据库创建新键。

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

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

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

于 2009-04-13T13:56:58.347 回答
5

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

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

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

于 2009-04-12T22:44:11.897 回答
3

我知道你能做的最好的事情就是使用output 子句。假设您有 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 存储在第三个交叉引用表中。

于 2009-04-12T22:33:49.877 回答
2

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

将 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 来生成插入语句。

于 2009-04-12T22:40:00.970 回答
2

有没有办法通过 INSERT INTO SELECT FROM 进行此更新,这样我就不必手动处理每条记录?

由于您不想手动执行,而是自动执行,因此请创建一个触发器,MV6.Posts以便在插入UPDATE时自动发生。MV5.PostsMV6.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
于 2009-04-12T22:50:01.977 回答
1

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

但是,您可以使用触发器来实现您想要做的事情。

于 2009-04-12T22:33:32.733 回答
1

在 MV6.Post.OldMV5Id 中创建一列

在 MV6.Post 中插入 select .. from MV5.Post

然后更新 MV5.Post.MV6ID

于 2009-04-12T22:44:53.657 回答