Hier ist eine Möglichkeit, die sich leicht auf drei verwandte Tabellen skalieren lässt.
Verwenden Sie MERGE, um die Daten in die Kopiertabellen einzufügen, damit Sie die alten und neuen IDENTITY-Werte in eine Steuertabelle ausgeben und für die Zuordnung verwandter Tabellen verwenden können.
Die eigentliche Antwort ist nur zwei Anweisungen zum Erstellen von Tabellen und drei Zusammenführungen. Der Rest ist das Einrichten und Herunterfahren von Beispieldaten.
USE tempdb;
--## Create test tables ##--
CREATE TABLE Customers(
[Id] INT NOT NULL PRIMARY KEY IdENTITY,
[Name] NVARCHAR(200) NOT NULL
);
CREATE TABLE Orders(
[Id] INT NOT NULL PRIMARY KEY IdENTITY,
[CustomerId] INT NOT NULL,
[OrderDate] DATE NOT NULL,
CONSTRAINT [FK_Customers_Orders] FOREIGN KEY ([CustomerId]) REFERENCES [Customers]([Id])
);
CREATE TABLE OrderItems(
[Id] INT NOT NULL PRIMARY KEY IdENTITY,
[OrderId] INT NOT NULL,
[ItemId] INT NOT NULL,
CONSTRAINT [FK_Orders_OrderItems] FOREIGN KEY ([OrderId]) REFERENCES [Orders]([Id])
);
CREATE TABLE Customers2(
[Id] INT NOT NULL PRIMARY KEY IdENTITY,
[Name] NVARCHAR(200) NOT NULL
);
CREATE TABLE Orders2(
[Id] INT NOT NULL PRIMARY KEY IdENTITY,
[CustomerId] INT NOT NULL,
[OrderDate] DATE NOT NULL,
CONSTRAINT [FK_Customers2_Orders2] FOREIGN KEY ([CustomerId]) REFERENCES [Customers2]([Id])
);
CREATE TABLE OrderItems2(
[Id] INT NOT NULL PRIMARY KEY IdENTITY,
[OrderId] INT NOT NULL,
[ItemId] INT NOT NULL,
CONSTRAINT [FK_Orders2_OrderItems2] FOREIGN KEY ([OrderId]) REFERENCES [Orders2]([Id])
);
--== Populate some dummy data ==--
INSERT Customers(Name)
VALUES('Aaberg'),('Aalst'),('Aara'),('Aaren'),('Aarika'),('Aaron'),('Aaronson'),('Ab'),('Aba'),('Abad');
INSERT Orders(CustomerId, OrderDate)
SELECT Id, Id+GETDATE()
FROM Customers;
INSERT OrderItems(OrderId, ItemId)
SELECT Id, Id*1000
FROM Orders;
INSERT Customers2(Name)
VALUES('Zysk'),('Zwiebel'),('Zwick'),('Zweig'),('Zwart'),('Zuzana'),('Zusman'),('Zurn'),('Zurkow'),('ZurheIde');
INSERT Orders2(CustomerId, OrderDate)
SELECT Id, Id+GETDATE()+20
FROM Customers2;
INSERT OrderItems2(OrderId, ItemId)
SELECT Id, Id*1000+10000
FROM Orders2;
SELECT * FROM Customers JOIN Orders ON Orders.CustomerId = Customers.Id JOIN OrderItems ON OrderItems.OrderId = Orders.Id;
SELECT * FROM Customers2 JOIN Orders2 ON Orders2.CustomerId = Customers2.Id JOIN OrderItems2 ON OrderItems2.OrderId = Orders2.Id;
--== ** START ACTUAL ANSWER ** ==--
--== Create Linkage tables ==--
CREATE TABLE CustomerLinkage(old INT NOT NULL PRIMARY KEY, new INT NOT NULL);
CREATE TABLE OrderLinkage(old INT NOT NULL PRIMARY KEY, new INT NOT NULL);
--== Copy Header (Customers) rows and record the new key ==--
MERGE Customers2
USING Customers
ON 1=0 -- we just want an insert, so this forces every row as unmatched
WHEN NOT MATCHED THEN
INSERT (Name) VALUES(Customers.Name)
OUTPUT Customers.Id, INSERTED.Id INTO CustomerLinkage;
--== Copy Detail (Orders) rows using the new key from CustomerLinkage and record the new Order key ==--
MERGE Orders2
USING (SELECT Orders.Id, CustomerLinkage.new, Orders.OrderDate
FROM Orders
JOIN CustomerLinkage
ON CustomerLinkage.old = Orders.CustomerId) AS Orders
ON 1=0 -- we just want an insert, so this forces every row as unmatched
WHEN NOT MATCHED THEN
INSERT (CustomerId, OrderDate) VALUES(Orders.new, Orders.OrderDate)
OUTPUT Orders.Id, INSERTED.Id INTO OrderLinkage;
--== Copy Detail (OrderItems) rows using the new key from OrderLinkage ==--
MERGE OrderItems2
USING (SELECT OrderItems.Id, OrderLinkage.new, OrderItems.ItemId
FROM OrderItems
JOIN OrderLinkage
ON OrderLinkage.old = OrderItems.OrderId) AS OrderItems
ON 1=0 -- we just want an insert, so this forces every row as unmatched
WHEN NOT MATCHED THEN
INSERT (OrderId, ItemId) VALUES(OrderItems.new, OrderItems.ItemId);
--== ** END ACTUAL ANSWER ** ==--
--== Display the results ==--
SELECT * FROM Customers2 JOIN Orders2 ON Orders2.CustomerId = Customers2.Id JOIN OrderItems2 ON OrderItems2.OrderId = Orders2.Id;
--== Drop test tables ==--
DROP TABLE OrderItems;
DROP TABLE OrderItems2;
DROP TABLE Orders;
DROP TABLE Orders2;
DROP TABLE Customers;
DROP TABLE Customers2;
DROP TABLE CustomerLinkage;
DROP TABLE OrderLinkage;
Wenn ich das in der Vergangenheit gemacht habe, habe ich es ungefähr so gemacht:
Sichern Sie beide Datenbanken.
Kopieren Sie die Zeilen, die Sie von der ersten Datenbank in die zweite verschieben möchten, in eine neue Tabelle ohne
IDENTITY
Spalte.Hinweis: Wir werden die obigen Tabellen als "temporär" bezeichnen. Ich empfehle Ihnen jedoch dringend, sie in ihrer eigenen Datenbank zu speichern und diese auch zu sichern, wenn Sie fertig sind.
DBCC CHECKIDENT
diese Option , um den nächstenIDENTITY
Wert für die Zieltabelle auf 1 zu verschieben, der über den für die Verschiebung erforderlichen Wert hinausgeht. Dadurch bleibt ein offener Block mit X-IDENTITY
Werten übrig, den Sie den Zeilen zuweisen können, die aus der ersten Datenbank übernommen werden.IDENTITY
Wert für die Zeilen aus der ersten Datenbank und den neuen Wert, den sie in der zweiten Datenbank verwenden.Beispiel: Sie verschieben 473 Zeilen, die einen neuen
IDENTITY
Wert benötigen , von der ersten Datenbank in die zweite. PerDBCC CHECKIDENT
ist der nächste Identitätswert für diese Tabelle in der zweiten Datenbank derzeit 1128. Verwenden SieDBCC CHECKIDENT
diese Option, um den Wert auf 1601 zu setzen. Anschließend füllen Sie Ihre Zuordnungstabelle mit den aktuellen Werten für dieIDENTITY
Spalte aus Ihrer übergeordneten Tabelle als alte Werte undROW_NUMBER()
weisen mit der Funktion die Nummern 1128 bis 1600 als neue Werte zu.Aktualisieren Sie mithilfe der Zuordnungstabelle die Werte in der
IDENTITY
Spalte, die normalerweise in der temporären übergeordneten Tabelle enthalten ist.SET IDENTITY_INSERT <parent> ON
mit die aktualisierten übergeordneten Zeilen aus der temporären übergeordneten Tabelle in die zweite Datenbank ein.HINWEIS: Wenn einige der untergeordneten Tabellen
IDENTITY
eigene Werte haben, wird dies ziemlich kompliziert. Meine eigentlichen Skripte (teilweise von einem Anbieter entwickelt, sodass ich sie nicht wirklich freigeben kann) behandeln Dutzende von Tabellen und Primärschlüsselspalten, einschließlich einiger, die numerische Werte nicht automatisch inkrementieren. Dies sind jedoch die grundlegenden Schritte.Ich habe die Zuordnungstabellen nach der Migration beibehalten, was den Vorteil hatte, dass wir einen "neuen" Datensatz basierend auf einer alten ID finden konnten.
Es ist nicht für schwache Nerven, und muss, muss, muss ( im Idealfall getestet werden mehrere Male) in einer Testumgebung.
UPDATE: Ich sollte auch sagen, dass ich mir trotzdem keine großen Sorgen darüber gemacht habe, ID-Werte zu "verschwenden". Ich habe meine ID-Blöcke in der zweiten Datenbank so eingerichtet, dass sie 2-3 Werte größer sind als erforderlich, um sicherzustellen, dass ich nicht versehentlich mit vorhandenen Werten kollidiere.
Ich verstehe sicherlich, dass ich während dieses Prozesses nicht Hunderttausende potenziell gültiger IDs überspringen möchte, insbesondere wenn der Prozess wiederholt wird (meiner wurde letztendlich über einen Zeitraum von 30 Monaten insgesamt etwa 20 Mal ausgeführt). Im Allgemeinen kann man sich jedoch nicht darauf verlassen, dass ID-Werte automatisch inkrementiert werden, um ohne Lücken sequentiell zu sein. Wenn eine Zeile erstellt und zurückgesetzt wird, verschwindet der Wert für die automatische Inkrementierung für diese Zeile. Die nächste hinzugefügte Zeile hat den nächsten Wert, und die aus der zurückgerollten Zeile wird übersprungen.
quelle
Customer-Order-OrderItem
oderCountry-State-City
. Wenn die drei Tabellen zusammen gruppiert sind, sind sie in sich geschlossen.Ich verwende eine Tabelle aus der
WideWorldImporters
Datenbank, bei der es sich um die neue Beispieldatenbank von Microsoft handelt. Auf diese Weise können Sie mein Skript so ausführen, wie es ist. Sie können aus einer Sicherung dieser Datenbank herunterladen hier .Quelltabelle (diese existiert im Beispiel mit Daten).
Zieltabelle:
Führen Sie nun den Export ohne Identitätsspaltenwert durch. Beachten Sie, dass ich nicht in die Identitätsspalte einfüge
VehicleTemperatureID
und auch nicht aus derselben auswähle.Um die zweite Frage zu FK-Einschränkungen zu beantworten, lesen Sie bitte diesen Beitrag. Besonders Abschnitt unten.
quelle