【问题标题】:Stuck trying to migrate two tables from one DB to another DB试图将两个表从一个数据库迁移到另一个数据库时卡住了
【发布时间】:2009-06-15 13:05:30
【问题描述】:

我正在尝试将一些数据从旧数据库中的两个表迁移到新数据库。

问题是我希望在新数据库中为要导入的第一个表生成新的主键。这很简单。

但是旧数据库中的第二张表对第一张表有外键依赖。所以当我想从第二个表迁移旧数据时,外键不再匹配。

是否有任何技巧/最佳实践可以帮助我迁移数据?

严重注意:我无法更改新表的当前架构,新表没有任何“旧 id”列。

让我们使用下表架构:-

Old Table1              New Table1
ParentId INT PK         ParentId INT PK
Name VARCHAR(50)        Name VARCHAR(50)

Old Table 2             New Table 2
ChildId INT PK          ChildId INT PK
ParentId INT FK         ParentId INT FK     
Foo VARCHAR(50)         Foo VARCHAR(50)

所以表架构是相同的。

想法?

编辑:

对于那些询问的人,RDBMS 是 Sql Server 2008。我没有指定软件,因为我希望我能用一些通用的 T-Sql 得到一个不可知的答案:P

【问题讨论】:

  • Name 和 Foo 是唯一的吗?如果是这样,您可以加入其中以找出旧 ID 是什么...
  • 哪个 RDBMS?您使用什么方法导入数据?
  • @Pure.Krome:Egads,伙计,我不认为你可以在这里绕过光标。讨厌这么说,但我认为这是你最好的解决方案。我只希望你有相对较小的数据集。
  • 没有问题 :) 光标很好。这是一次迁移。我会确保将其设为 FAST_FORWARD 游标。只是好奇是否还有其他技巧偷窥使用。干杯队友:)

标签: sql sql-server migration


【解决方案1】:

我认为您需要分两步完成此操作。

您需要导入旧表并保留旧表(并生成新表)。然后,一旦它们在新数据库中并且具有新旧 ID,您就可以使用旧 ID 来关联新 ID,然后删除旧 ID。

您可以通过导入临时(即它们将被丢弃)表来做到这一点,然后插入到永久表中,省去旧的 id。

或直接导入到新表中(修改架构以保存旧 id),然后在不再需要旧 ​​id 时删除它们。

编辑:

好的,感谢 cmets here 和其他答案,我对您正在寻找的内容更加清楚。我敲了这个,我想它会做你想做的。

基本上没有游标,它逐行遍历父表,并插入新的子行和该父行的所有子行,保持新 id 的同步。 我试过了,它应该可以工作,它不需要对表的独占访问,并且应该比游标快几个数量级。

declare @oldId as int
declare @newId as int

select @oldId = Min(ParentId) from OldTable1 

while not @oldId is null
begin
    Insert Into NewTable1 (Name)
    Select Name from OldTable1 where ParentId = @oldId

    Select @newId = SCOPE_IDENTITY()

    Insert Into NewTable2 (ParentId, Foo)
    Select @newId, Foo From OldTable2 Where ParentId = @oldId

    select @oldId = Min(ParentId) from OldTable1 where ParentId > @oldId

end

希望这会有所帮助,

【讨论】:

  • 目前,“新表 1”中已经有一些数据。因此,如果我将旧表数据插入到临时表(例如 #blah 或其他)或变量表中,我不确定如何将其与插入到最终“新表 1”中的行关联起来'。你是说我的临时表应该有 3 个字段吗?身份 PK、(旧)ParentId、(新)ParentId?我只是不确定如何在插入时找出新的 ID。?
【解决方案2】:

好吧,我想您必须确定其他标准才能创建像 oldPK => newPK 这样的地图(例如:Name 字段是否相等?

然后你可以确定新的PK匹配旧的PK,并相应地调整ParentID

您还可以做一个小技巧:在原始 Table1 中添加一个新列,该列存储复制记录的新 PK 值。然后,您可以轻松复制 Table2 的值,将它们指向新列的值,而不是旧的 PK。

编辑:我正在尝试提供一些示例代码来说明我的小技巧的意思。我没有改变原来的数据库结构,但我现在使用的是临时表。

好的,您可以尝试以下操作:

1) 创建临时表来保存旧表的值,另外,它会获得一个新的 PK:

CREATE TABLE #tempTable1
(
    newPKField INT,
    oldPKField INT,
    Name VARCHAR(50)
)

2) 将旧表中的所有值插入到临时表中,计算新的 PK,复制旧的 PK:

INSERT INTO #tempTable1
SELECT
   newPKValueHere AS newPKField,
   ParentID as oldPKField,
   Name
FROM
   Table1

3) 将值复制到新表中

INSERT INTO NewTable1
SELECT
   newPKField as ParentId,
   Name
FROM
   #tempTable1

4) 将 Table2 中的值复制到 NewTable2

INSERT INTO NewTable2
SELECT
   ChildID,
   t.newPKField AS ParentId,
   Foo
FROM 
   Table2
   INNER JOIN #tempTable1 t ON t.ParentId = parentId

这应该可以。请注意,这只是伪 T-SQL 代码——我没有在真实数据库上测试过!但是,它应该接近您的需要。

【讨论】:

  • 我不懂“小把戏”。你能用一些代码解释一下吗?
  • 这很可爱 - 更改 old 数据库的架构并在那里做繁重的工作。
  • @Pure.Krome,我认为“小技巧”是在 OLD 数据库中添加一个“新 id”列,然后在复制 Table2 时使用此数据进行插入。跨度>
  • @Pure.Krome:我的意思如下:1)将新列 newPK 添加到原始 Table1 2)将 Table1 中的所有项目复制到新 Table1,使用新 ID 更新旧 Table1 中的每个条目the newPK column 3)复制Table2中的所有项目,引用Table1的newPK列中的值
  • 顺便说一句:您甚至不必修改原始表。您可以创建一个临时内存表,其中包含 Table1 中具有新列的所有字段。然后选择进入这个临时表。然后从临时表复制到新的 Table1 更新 newPK 字段,然后复制 Table2 中的条目。
【解决方案3】:

你能改变旧表的架构吗?如果是这样,您可以在旧表上放置一个“新 id”列,并将其用作参考。

您可能必须在新表上逐行插入,然后检索 scope_identity,将其存储在旧表中。但是对于 table2,你可以加入旧的 table1 并获取 new_id。

【讨论】:

  • 我担心我必须使用光标来执行此操作。我无法更改架构。 (但我当然可以使用临时表)。
  • 是的,游标或类似 SSIS 的东西 - 可以有几个数据流。第一个从表 A 中选择 *,通过 OLEDB 转换(插入,然后将 scope_identity 选择到数据流中的新列中),然后将具有新 id 字段的记录保存到临时表中。然后,第二个数据流检索表 b,并在 old_id 上查找临时表
【解决方案4】:

首先 - 你甚至不能有一些你以后可以删除的临时架构吗?!那会让生活更轻松。假设你不能:

如果您很幸运(并且如果您可以保证不会同时发生其他插入),那么当您将 Table1 的数据插入新表时,您可能会依靠插入的顺序来作弊.

然后,您可以创建一个按行数连接 2 个表的视图,以便您可以将键相互关联。这样一来,您就离能够识别新 Table2 的“ParentId”更近了一步。

【讨论】:

    【解决方案5】:

    从您的问题中我不确定您使用的是什么数据库软件,但如果可以选择临时表,请创建一个临时表,其中包含 table1 的原始主键和 table1 的新主键。然后使用 table2 的副本创建另一个临时表,使用您之前创建的“旧键,新键”表更新副本,然后使用“插入到从选择中”(或适用于您的数据库的任何命令)复制将临时表修改为永久位置。

    【讨论】:

    • 我不认为数据库软件很重要——我希望得到一些 T-SQL(独立于软件)的​​答案。也就是说,你如何为每个旧 ID 将新的 PK 插入到这个临时表中?你是否也建议使用光标?
    • 我不确定这是否需要光标。用户定义的函数和 T-SQL 支持的 UPDATE...FROM 结构的组合可能会成功。如果您在东部时间中午之前没有得到可接受的答案,我会在午餐时尝试模拟一些东西。
    • 干杯伙伴 :) 我目前正在使用光标解决方案 .. 因为这就是我所能看到的(现在)如何做到这一点。非常感谢。
    • 我希望光标解决方案能奏效。无论如何,我可能最终会尝试做一个非光标的,只是看看它是否可以完成。
    • 干杯伙伴:)期待它:)
    【解决方案6】:

    去年夏天,我有幸深入研究迁移脚本。我正在使用 Oracle 的 PL/SQL 来完成这项任务。但是你没有提到你使用的是什么技术?您要将数据迁移到什么位置? SQL 服务器?甲骨文? MySQL?

    方法是从 table1 插入一行返回生成的新主键(可能由 SEQUENCE [in Oracle])然后从 table2 插入依赖记录,将它们的外键值更改为第一个 INSERT 返回的值.除非您可以指定要将数据迁移到哪个 DBMS,否则无法为您提供更好的帮助。

    【讨论】:

      【解决方案7】:

      下面的伪代码应该适合你

      CREATE TABLE newtable1
        ParentId INT PK
        OldId   INT
        Name     VARCHAR(50)
      
      CREATE TABLE newtable2
        ChildId    INT pk
        ParentId   INT FK
        OldParent  INT
        Foo        VARCHAR(50)   
      
        INSERT INTO newtable1(OldId, Name)
        SELECT  ParentId, Name FROM oldtable1
      
        INSERT INTO newtable2(OldParent, Foo)
        SELECT ParentId, Foo FROM oldtable2
      
      UPDATE newtable2 SET ParentId = (
        SELECT n.ParentId 
        FROM   newtable1 AS n
        WHERE  n.OldId = newtable2.oldParent
      )
      
      ALTER TABLE newtable1 DROP OldId
      ALTER TABLE newtable2 DROP OldParent
      

      【讨论】:

      • 嗯。我看不出 Update 子句是如何工作的。您正在尝试设置 ParentId .. 我不想这样做。我需要它自动生成...???
      • 当然在第二张表上,您希望 childId 自动生成,ParentId 是父表的主键。
      猜你喜欢
      • 1970-01-01
      • 2020-03-16
      • 2023-01-11
      • 1970-01-01
      • 1970-01-01
      • 2018-06-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-06
      相关资源
      最近更新 更多