kev*_*vin 9 foreign-key sql-server identity
我想将数据从一个数据库迁移到另一个数据库。表模式完全相同:
CREATE TABLE Customers(
[Id] INT NOT NULL PRIMARY KEY IDENTITY,
(some other columns ......)
);
CREATE TABLE Orders(
[Id] INT NOT NULL PRIMARY KEY IDENTITY,
[CustomerId] INT NOT NULL,
(some other columns ......),
CONSTRAINT [FK_Customers_Orders] FOREIGN KEY ([CustomerId]) REFERENCES [Customers]([Id])
)
Run Code Online (Sandbox Code Playgroud)
两个数据库有不同的数据,因此同一个表的新身份密钥在两个数据库中会不同。这不是问题;我的目标是将新数据附加到现有数据中,而不是完全替换整个表的所有数据。但是我想维护插入数据的所有父子关系。
如果我使用 SSMS 的“生成脚本”功能,脚本将尝试使用相同的 ID 插入,这会与目标数据库中的现有数据发生冲突。如何仅使用数据库脚本复制数据?
我希望目的地的标识列从其最后一个值正常继续。
Customers
没有任何其他UNIQUE NOT NULL
约束。它是确定在其他列重复数据(我使用的是Customers
与Orders
只是作为一个例子在这里,所以我没有解释整个故事)。问题是关于任何一对 N 关系。
Mis*_*goo 11
这是一种可以轻松扩展到三个相关表的方法。
使用 MERGE 将数据插入到副本表中,以便您可以将旧的和新的 IDENTITY 值输出到控制表中,并将它们用于相关表的映射。
实际答案只是两个 create table 语句和三个合并。其余的是样本数据设置和拆卸。
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;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
24830 次 |
最近记录: |