Here is how it is implemented in our MssqlMerge, kind of "maintain the mapping from old-to-new ID" suggested by @WillA
Let's say we have two tables:
- [Parent] ([ParentID] PRIMARY KEY IDENTITY, [Name])
- [Child] ([ChildID] PRIMARY KEY IDENTITY, [ParentID] REFERENCES [Parent] ([ParentID]), [Name]).
Now when we merge [Parent] rows to from one db to another, we do the following steps:
a. in target DB create mapping table with columns (SourceID, TargetID)
b. INSERT [Parent] row with data from source table, without specifying ID:
INSERT INTO [Parent] ([Name])
OUTPUT 123 /* Source ID */, INSERTED.[ParentID] INTO [mapping]
VALUES ('Source parent #1');
c. INSERT [Child] row, taking [ParentID] from mapping:
INSERT INTO [Child] ([ParentID], [Name])
VALUES (
(SELECT [ParentID] FROM [mapping] WHERE [SourceID] = 123 /* Source ID */),
'Source child #1');
Filters can be applied to the Parent table rows. Child rows are filtered to include only records with ParentID corresponding to the Parent table filter. Going further, we may have a table like Grandchild referencing Child on ChildID and we may select to import Grandchild rows as well, filtering only rows having ChildID related to selected parents. And so on for any foreign key relations depth, each table is merged with its own mapping.
Mapping tables can be left in the target database after merge and can be useful for a number of goals:
- you can split large merge into smaller parts, for example merge lookup data first and then operational data
- mapping tables can be used to: identify merge result rows, to match these rows with source db or even to rollback merge without need to restore the full backup.
Information about dependent tables is taken from sys.foreign_keys and sys.foreign_key_columns.
Currently the major limitation of this approach is that it can not be used for tables participating in cycled foreign keys (like A references B and B references A at the same time). There is the way around this by breaking the cycle - ignoring one of the foreign keys and then UPDATEing them after INSERTs completion, but that's the subject of further improvements.