合并数据库如何处理重复的PK

时间:2009-07-07 18:57:00

标签: sql database merge

我们有三个按地区分开的数据库,一个在LA,SF和NY。所有数据库共享相同的模式,但包含特定于其区域的数据。我们希望将这些数据库合并为一个并对其进行镜像。我们需要保留每个区域的数据,但是将它们合并到一个db中。这给我们带来了很多问题,例如我们肯定会有重复的主键,外键可能会无效。

我希望找到一个有过这样一个任务经验的人,他可以提供一些关于我们如何完成合并的技巧,策略和经验。

例如,一个想法是创建复合键,然后更改我们的代码和sprocs以通过复合键(region / original pk)查找数据。但这要求我们改变所有代码和代码。

另一个想法是只导入数据并让它生成新的PK,然后更新所有对新PK的FK引用。这样我们就不必更改任何代码。

欢迎任何经验!

6 个答案:

答案 0 :(得分:3)

我没有这方面的第一手经验,但在我看来,你应该能够独特地映射PK - >每个服务器的新PK。例如,生成新的PK,使得来自LA服务器的数据具有PK%3 == 2,SF具有PK%3 == 1,并且NY具有PK%3 == 0.并且因为,正如我理解您的问题,无论如何服务器只将FK关系存储到自己的数据中,您可以以相同的方式更新FK。

NewLA = OldLA*3-1
NewSF = OldLA*3-2
NewNY = OldLA*3

然后您可以合并这些并且没有重复的PK。正如您已经说过的,这基本上只是生成新的PK,但是以这种方式构造它可以让您轻松更新您的FK(假设,正如我所做的那样,每个服务器上的数据都是隔离的)。祝你好运。

答案 1 :(得分:1)

BEST:为RegionCode添加一个列,并将其包含在您的PK中,但您不想完成所有的工作。

HACK:如果您的ID是INT,快速解决方法是在导入时为每个键添加基于区域的固定值。 INT可以大到:2,147,483,647

本地服务器数据:

LA IDs: 1,2,3,4,5,6
SF IDs: 1,2,3,4,5
NY IDs: 1,2,3,4,5,6,7,9

向LA的ID添加100000000 将200000000添加到SF的ID中 添加300000000到NY的ID

组合服务器数据:

LA IDs: 100000001,100000002,100000003,100000004,100000005,100000006
SF IDs: 200000001,200000002,200000003,200000004,200000005
NY IDs: 300000001,300000002,300000003,300000004,300000005,300000006,300000007,300000009

答案 2 :(得分:1)

我已经这样做了,我说改变你的密钥(选择方法)而不是改变你的代码。您总是会错过存储过程或引入错误。通过更改数据,编写测试以查找孤立记录或验证事物是否正确匹配非常容易。随着代码更改,特别是正常运行的代码,很容易错过。

答案 3 :(得分:0)

您可以做的一件事是使用区域数据设置表以使用GUID。这样,每个区域中的主键都是唯一的,您可以混合和匹配数据(将数据从一个区域导入另一个区域)。对于具有共享数据的表(如类型表),您可以保持主键的方式(因为它们应该在任何地方都相同)。

以下是有关GUID的一些信息: http://www.sqlteam.com/article/uniqueidentifier-vs-identity

也许SQL Server Management Studio允许您将列转换为轻松使用GUID。我希望如此!

祝你好运。

答案 4 :(得分:0)

我在这种情况下所做的是:

  1. 使用相同的架构创建新的数据库 但只有桌子。没有pk fk,检查 等
  2. 将数据从DB1传输到此 source db
  3. 表示目标数据库中的每个表 找到PK的最高编号
  4. 表示源中的每个表 数据库更新他们的pk,fk等 从(顶部数字+ 1)开始 来自目标数据库
  5. 表示目标数据库中的每个表 将身份插入设置为
  6. 将源数据库中的数据导入目标 分贝
  7. 表示目标数据库中的每个表 将身份插入设置为关闭
  8. clear source db
  9. 重复DB2

答案 5 :(得分:0)

正如Jon所说,我会使用GUID来解决合并任务。我看到两种不同的解决方案需要GUID:

1)永久更改数据库架构,以使用GUID而不是INTEGER(IDENTITY)作为主键。

这通常是一个很好的解决方案,但如果你有很多非SQL代码以某种方式绑定到你的标识符的工作方式,它可能需要相当多的代码更改。 可能因为您合并数据库,您可能无论如何都需要更新您的应用程序,以便它仅使用基于登录用户的一个区域数据等。

2)暂时添加GUID仅用于迁移目的,迁移数据后删除它们:

  

这个有点棘手,但是一旦你编写了这个迁移脚本,你可以(重新)多次运行它来再次合并数据库,以防你第一次搞砸它。这是一个例子:

Table: PERSON (ID INT PRIMARY KEY, Name VARCHAR(100) NOT NULL)
Table: ADDRESS (ID INT PRIMARY KEY, City VARCHAR(100) NOT NULL, PERSON_ID INT)

您的更改脚本是(请注意,对于所有PK,我们会自动生成GUID):

ALTER TABLE PERSON ADD UID UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWID())
ALTER TABLE ADDRESS ADD UID UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWID())
ALTER TABLE ADDRESS ADD PERSON_UID UNIQUEIDENTIFIER NULL

然后更新FK以与INTEGER一致:

--// set ADDRESS.PERSON_UID
UPDATE  ADDRESS
SET     ADDRESS.PERSON_UID = PERSON.UID
FROM    ADDRESS
INNER JOIN PERSON
    ON  ADDRESS.PERSON_ID = PERSON.ID

您为所有PK(自动生成GUID)和FK(如上所示更新)执行此操作。

现在您创建目标数据库。在此目标数据库中,还可以为所有PK和FK添加UID列。同时禁用所有FK约束。

现在您从每个源数据库插入到目标数据库(注意:我们不插入PK和整数FK):

INSERT INTO TARGET_DB.dbo.PERSON (UID, NAME)
SELECT UID, NAME FROM SOURCE_DB1.dbo.PERSON

INSERT INTO TARGET_DB.dbo.ADDRESS (UID, CITY, PERSON_UID)
SELECT UID, CITY, PERSON_UID FROM SOURCE_DB1.dbo.ADDRESS

从所有数据库插入数据后,运行与原始数据库相反的代码,使整数FK与目标数据库上的GUID一致:

--// set ADDRESS.PERSON_ID
UPDATE  ADDRESS
SET     ADDRESS.PERSON_ID = PERSON.ID
FROM    ADDRESS
INNER JOIN PERSON
    ON  ADDRESS.PERSON_UID = PERSON.UID

现在您可以删除所有UID列:     ALTER TABLE PERSON DROP COLUMN UID     ALTER TABLE ADDRESS DROP COLUMN UID     ALTER TABLE ADDRESS DROP COLUMN PERSON_UID

所以最后你应该得到一个相当长的迁移脚本,它应该为你完成这项工作。重点是 - 可行

注意:此处所有内容均未经过测试。