Sql FKs链接的表中存在重复行

Sql FKs链接的表中存在重复行,sql,sql-server,database,tsql,Sql,Sql Server,Database,Tsql,我试图通过复制数据库中的现有数据来生成一些用于测试的数据。有许多表由FKs链接,我希望保持相同的数据配置文件。我认为用一个例子来解释是最简单的: 客户编号 名称 年龄 1. 弗莱德 20 2. 上下快速移动 30 3. 乔 40 您可以使用OUTPUT子句: DECLARE @ids TABLE (customerid int, Name varchar(255), age int); INSERT INTO Customers (Name, Age) OUTPUT inserted.

我试图通过复制数据库中的现有数据来生成一些用于测试的数据。有许多表由FKs链接,我希望保持相同的数据配置文件。我认为用一个例子来解释是最简单的:

客户编号 名称 年龄 1. 弗莱德 20 2. 上下快速移动 30 3. 乔 40
您可以使用
OUTPUT
子句:

DECLARE @ids TABLE (customerid int, Name varchar(255), age int);

INSERT INTO Customers (Name, Age)
    OUTPUT inserted.customerid, Name, Age INTO @ids
    SELECT Name, Age
    FROM Customers
    WHERE Age > 18;
然后,您可以对其他表使用
@ids

INSERT INTO invoices (CustomerID, Date)
    SELECT cnew.customerID, i.date
    FROM invoices i JOIN
         customers c
         ON i.customerID = c.customerID JOIN
         @ids cnew
         ON cnew.name = c.name AND cnew.age = c.age;

@id
s中的附加列是可用的,因此您可以将批处理与现有列相匹配。不幸的是,您不再具有id,因此希望其他一些列的组合能够唯一地标识原始客户。

您可以使用
MERGE
以及
OUTPUT
子句来捕获新数据到旧数据的映射,例如

DECLARE @CustomerMapping TABLE (OldCustomerID INT NOT NULL, NewCustomerID INT NOT NULL);

MERGE Customers AS t
USING 
(   SELECT  CustomerID, Name, Age 
    FROM    Customers 
    WHERE   Age > 18
) AS s
    ON 1 = 0 -- THIS WILL NEVER BE TRUE SO WILL ALWAYS BE "NOT MATCHED"
WHEN NOT MATCHED THEN 
    INSERT (Name, Age)
    VALUES (s.Name, s.Age)
OUTPUT s.CustomerID, inserted.CustomerID
    INTO @CustomerMapping (OldCustomerID, NewCustomerID);
然后,您可以使用此ID映射对发票重复相同操作:

DECLARE @InvoiceMapping TABLE (OldInvoiceID INT NOT NULL, NewInvoiceID INT NOT NULL);

MERGE Invoices AS t
USING 
(   SELECT  i.InvoiceID,
            CustomerID = m.NewCustomerID,
            i.Date
    FROM    Invoices AS i
            INNER JOIN @CustomerMapping AS m
                ON m.OldCustomerID = i.CustomerID
) AS s
    ON 1 = 0
WHEN NOT MATCHED THEN
    INSERT (CustomerID, Date)
    VALUES (s.CustomerID, s.Date)
OUTPUT s.InvoiceID, inserted.InvoiceID
    INTO @InvoiceMapping (OldInvoiceID, NewInvoiceID);
然后,您可以使用发票映射插入行项目:

INSERT LineItems (InvoiceID, Item, Price, Qty)
SELECT  m.NewInvoceID,
        li.Item,
        li.Price,
        li.Qty
FROM    LineItems AS li
        INNER JOIN @InvoiceMapping AS m
            ON m.OldInvoiceID = li.InvoiceID;
由于不需要输出(除非行项有更多的子项,在这种情况下,您需要再次使用
MERGE
并像以前一样捕获输出),因此标准的
INSERT
将在此处执行

必须执行仅插入的伪
合并
,以便捕获新ID和旧ID,使用正常的
插入
,您只能访问
输出
子句中插入的字段

由于bug的数量,在SQL Server中使用
MERGE
总是有(合理的)顾虑,但是,只要您使用表作为目标并且只插入新数据,我所知道的bug都不会影响此场景


合并是这里缺少的一部分,我曾尝试使用输出来制作映射,但无法获得旧ID。谢谢!