将关系数据从数据库复制到数据库

时间:2020-03-05 18:52:20  来源:igfitidea点击:

编辑:让我完全重述一下,因为我不确定是否有像我最初描述的那样的XML方式。

另一个编辑:这需要是一个可重复的过程,并且必须能够以可以在Ccode中调用的方式进行设置。

在数据库A中,我有一组与PK和FK相关的表。假设有一个父表以及子表和孙表。

我想将一组行从数据库A复制到具有相同名称的表和字段的数据库B。对于每个表,我都希望插入数据库B中的同一表中。但是,我不必使用相同的主键。复制例程必须为数据库B中的每一行创建新的PK,并且必须将这些PK传播到子行。换句话说,我保持数据之间的关系相同,但是不完全相同的PK和FK。

我们将如何解决?我愿意提出建议。 SSIS并未完全被排除在外,但在我看来并不像它会做这件事一样。我也愿意使用LINQ解决方案,或者使用类型化的数据集,或者使用某些XML,或者几乎可以在SQL Server 2005和/或者C(.NET 3.5)中使用的任何东西。最好的解决方案不需要SSIS,也不需要编写大量代码。但我承认,这种"最佳"解决方案可能不存在。

(我没有自己做这个任务,也没有约束;这是我的工作方式。)

解决方案

回答

转储XML方法并使用导入向导/ SSIS。

回答

首先,让我说SSIS是我们最好的选择。但是,要回答我们提出的问题...

我不相信我们将能够四处创建新的ID,尽管我们可以,但是我们将需要使用原始ID进行查找。

最好的获取方法是为表插入一条语句。这是执行SELECT来从XML样本中获取数据的代码示例:

declare @xml xml 
set @xml='<People Key="1" FirstName="Bob" LastName="Smith">
  <PeopleAddresses PeopleKey="1" AddressesKey="1">
    <Addresses Key="1" Street="123 Main" City="St Louis" State="MO" ZIP="12345" />
  </PeopleAddresses>
</People>
<People Key="2" FirstName="Harry" LastName="Jones">
  <PeopleAddresses PeopleKey="2" AddressesKey="2">
    <Addresses Key="2" Street="555 E 5th St" City="Chicago" State="IL" ZIP="23456" />
  </PeopleAddresses>
</People>
<People Key="3" FirstName="Sally" LastName="Smith">
  <PeopleAddresses PeopleKey="3" AddressesKey="1">
    <Addresses Key="1" Street="123 Main" City="St Louis" State="MO" ZIP="12345" />
  </PeopleAddresses>
</People>
<People Key="4" FirstName="Sara" LastName="Jones">
  <PeopleAddresses PeopleKey="4" AddressesKey="2">
    <Addresses Key="2" Street="555 E 5th St" City="Chicago" State="IL" ZIP="23456" />
  </PeopleAddresses>
</People>
'

select t.b.value('./@Key', 'int') PeopleKey,
    t.b.value('./@FirstName', 'nvarchar(50)') FirstName,
    t.b.value('./@LastName', 'nvarchar(50)') LastName
from @xml.nodes('//People') t(b)

select t.b.value('../../@Key', 'int') PeopleKey,
    t.b.value('./@Street', 'nvarchar(50)') Street,
    t.b.value('./@City', 'nvarchar(50)') City,
    t.b.value('./@State', 'char(2)') [State],
    t.b.value('./@Zip', 'char(5)') Zip
from 
@xml.nodes('//Addresses') t(b)

这是从XML中获取Nodes并解析出数据。为了从人们那里获得关系ID,我们使用../../进行链接。

回答

到目前为止,最简单的方法是Red Gate的SQL数据比较。我们可以将其设置为在一两分钟内完成我们描述的操作。

回答

我也喜欢Red Gate的SQL比较和数据比较,但是据我所知,它不能满足他对更改主键的要求。

如果可以选择跨数据库查询/链接服务器,则可以使用存储过程来完成,该存储过程将记录从DB A中的父/子复制到DB B的临时表中,然后在temp子表中添加新主键的列我们将在插入标头后进行更新。

我的问题是,如果记录没有相同的主键,我们如何确定它是否是新记录?还有其他候选密钥吗?如果这些是新表,为什么它们不能具有相同的主键?

回答

我用一组存储过程创建了相同的东西。

数据库B将具有其自己的主键,但会存储数据库A的主键以用于调试。这意味着我可以拥有多个数据库A!

数据通过链接服务器复制。不太快; SSIS更快。但是SSIS不适合初学者,并且编写与更改源表兼容的代码并不容易。

而且很容易从C#调用存储过程。

回答

我将其编写为存储过程的脚本,并使用"插入"来完成艰苦的工作。代码将采用表A的PK(可能是通过@@ Scope_Identity)。我假设表A的PK是一个Identity字段?

我们可以使用临时表,游标,或者我们可能更喜欢使用CLR,它可能会适合于这种操作。

我很惊讶地发现一个可以立即使用a)预定键或者b)标识字段(显然,表B和C没有它们)的工具。

回答

我们是否每次都要清除目标表,然后重新开始?这将与我们需要实施的解决方案有很大的不同。如果我们每次都进行一次完整的重新导入,则可以执行以下操作:

创建一个临时表或者表变量以记录父表的旧主键和新主键。

将父表数据插入目标位置,并使用OUTPUT子句捕获新ID,并将其与旧ID一起插入到临时表中。
注意:使用output子句非常有效,并且可以批量执行插入操作,而无需循环遍历要插入的每个记录。

插入子表数据。连接到临时表以检索所需的新外键。

可以使用T-SQL脚本,Ccode或者SSIS完成上述过程。我更喜欢SSIS。

回答

如果每次都添加,则可能需要保留一个永久表以跟踪源数据库主键和目标数据库主键之间的关系(至少对于父表而言)。如果需要将此类数据保留在目标数据库之外,则可以让SSIS从某种日志数据库甚至平面文件中存储/检索它。

如果父表中的字段组合可用于唯一地标识该记录,从而在目标数据库中"查找"该记录的主键,则可能会避免上述情况。

回答

我认为最有可能要使用的是类型化数据集。这不会是一个通用的解决方案。如果任何表发生更改,我们将不得不重新生成它们。但是根据我所得到的信息,这不是问题。表格不会有太大变化。

数据集将使在插入之后分层循环遍历数据并从数据库刷新PK变得相当容易。

回答

当处理类似的任务时,我只是创建了一组存储过程来完成这项工作。

由于我们指定的任务是非常自定义的,因此我们不太可能找到"准备使用"的解决方案。

只是给我们一些提示:

  • 如果数据库位于不同的服务器上,请使用链接服务器,因此我们可以简单地通过TSQL访问源表和目标表

在存储过程中:

  • 标识需要复制的父项-我们说主键是不同的,因此我们需要使用唯一的约束(如果对表进行了规范化,则应该能够定义它们)
  • 根据已标识的父项标识需要复制的子项,以检查其中的某些项是否已在目标数据库中,请再次使用唯一约束方法
  • 识别孙子项(与父子项逻辑相同)
  • 从最低级别开始复制数据(孙子,子女,父母)

不需要游标等,只需将立即结果存储在临时表中(如果在一个存储过程中工作则为表变量)

这种方法对我来说非常有效。

我们当然可以在主存储过程中添加参数,以便可以复制所有新记录或者仅复制指定的记录。

让我知道这是否有帮助。

回答

我认为我们可能正在寻找SQL Server实用程序tablediff.exe。

另请参见此线程。