5

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

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

在数据库 A 中,我有一组表,由 PK 和 FK 相关。比方说,一个带有子表和孙表的父表。

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

你会如何解决这个问题?我愿意接受建议。SSIS 没有被完全排除,但在我看来它不会做这个确切的事情。我也对 LINQ 中的解决方案持开放态度,或者使用类型化的数据集,或者使用一些 XML 的东西,或者任何可以在 SQL Server 2005 和/或 C# (.NET 3.5) 中工作的东西。最好的解决方案不需要 SSIS,也不需要编写大量代码。但我承认,这种“最佳”解决方案可能不存在。

(我没有自己完成这项任务,也没有限制;这就是给我的方式。)

4

11 回答 11

2

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

另请参阅此线程

于 2008-09-30T14:10:26.407 回答
1

首先,让我说 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 中获取节点并解析数据。为了从人们那里获取关系 ID,我们使用 ../../ 来上链。

于 2008-09-12T16:08:03.533 回答
0

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

于 2008-09-12T15:50:21.907 回答
0

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

于 2008-09-12T21:47:16.120 回答
0

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

如果跨数据库查询/链接服务器是一个选项,您可以使用存储过程来执行此操作,该存储过程将 DB A 中的父/子记录复制到 DB B 上的临时表中,然后在临时子表中为新主键添加一列插入标题后您将更新。

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

于 2008-09-13T16:38:31.067 回答
0

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

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

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

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

于 2008-09-16T10:24:45.400 回答
0

我会在存储过程中编写脚本,使用插入来完成艰苦的工作。您的代码将从表 A 中获取 PK(可能通过 @@Scope_Identity) - 我假设表 A 的 PK 是一个身份字段?

您可以使用临时表、游标,或者您可能更喜欢使用 CLR——它可能适合这种操作。

我会惊讶地发现一个工具可以通过 a) 预先确定的密钥或 b) 身份字段(显然表 B 和 C 没有它们)来完成此任务。

于 2008-09-16T11:33:06.953 回答
0

您是否每次都清除目标表然后重新开始?这将对您需要实施的解决方案产生重大影响。如果您每次都进行完整的重新导入,那么您可以执行以下操作:

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

将父表数据插入目标并使用OUTPUT子句捕获新 ID 并将它们与旧 ID 一起插入到临时表中。注意:使用输出子句是有效的,并且允许您进行批量插入,而无需循环遍历要插入的每条记录。

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

上述过程可以使用 T-SQL 脚本、C# 代码或 SSIS 完成。我更喜欢 SSIS。

于 2008-09-17T06:00:18.743 回答
0

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

如果父表中存在可用于唯一标识该记录并因此“找到”目标数据库中该记录的主键的字段组合,则您可能会避免上述情况。

于 2008-09-18T00:54:41.747 回答
0

我认为我最有可能使用的是类型化数据集。这不会是一个通用的解决方案;如果任何表发生变化,我们将不得不重新生成它们。但根据我被告知的情况,这不是问题。预计表格不会有太大变化。

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

于 2008-09-18T01:54:45.173 回答
0

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

由于您指定的任务非常自定义,因此您不太可能找到“即用型”解决方案。

只是给你一些提示:

  • 如果数据库在不同的服务器上,请使用链接服务器,这样您就可以通过 TSQL 访问源表和目标表

在存储过程中:

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

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

这种方法对我很有效。

您当然可以将参数添加到主存储过程,以便您可以复制所有新记录或仅复制您指定的记录。

让我知道这是否有帮助。

于 2008-09-30T14:05:32.393 回答