从一个表复制到另一个表并替换为SCOPE_IDENTITY

时间:2016-03-20 04:56:44

标签: sql-server tsql

我正在使用SQL Server 2014。

我通过将所有物理地址列移动到专用地址表来反规范化现有数据库,如下所示:

旧:

Customers (CustomerId, AddressLine1, AddressLine2, City, State, Country, etc )
Employees (EmployeeId, AddressLine1, AddressLine2, City, State, Country, etc )
Orders (OrderId, AddressLine1, AddressLine2, City, State, Country, etc )

新:

Addresses (AddressId, Street, City, State, Country, Zip )
Customers (CustomerId, AddressId, etc )
Employees (CustomerId, AddressId, etc )
Orders (CustomerId, AddressId, etc )

将每个表中的数据导入地址非常简单:

INSERT INTO Addresses (Street, City, State, Country)
    SELECT 
        CONCAT(AddressLine1, AddressLine2), City, State, Country) 
    FROM Customers
    UNION ALL
    SELECT 
        CONCAT(AddressLine1, AddressLine2), City, State, Country) 
    FROM Employees
    UNION ALL
    SELECT 
       CONCAT(AddressLine1, AddressLine2), City, State, Country) 
    FROM Orders

但是,如何为每个插入的行获取新的AddressId值并将其设置为Customers.AddressIdEmployees.AddressIdOrders.AddressId值?

...理想情况下,不使用获取单行的巨型循环,插入它,并使用SCOPE_IDENTITY进行更新。

2 个答案:

答案 0 :(得分:3)

假设

1)地址,客户,员工和订单具有以下PK:AdressId,CustomerId,EmployeeId,OrderId

2)dbo.Adresses.AdressId列(PK)具有IDENTITY属性

然后对于每个源表(客户等),您可以使用以下方法:

/*
-- Just once
CREATE TABLE #AffectedRows (
    SourceID    INT NOT NULL PRIMARY KEY,
    AdressID    INT NOT NULL
)
*/
SET XACT_ABORT ON
BEGIN TRAN
TRUNCATE TABLE #AffectedRows

MERGE dbo.Adresses a
USING dbo.Customers c ON a.AdressID = c.AdressID
WHEN NOT MATCHED 
    THEN 
    INSERT (City)
    VALUES (c.City)
OUTPUT c.CustomerId, inserted.AdressId INTO #AffectedRows;

UPDATE  c
SET     c.AdressId = ar.AdressId
FROM    dbo.Customers c
JOIN    #AffectedRows ar ON c.CustomerId = ar.SourceId
--WHERE c.AdressId IS NULL
COMMIT

SELECT * FROM dbo.Customers

答案 1 :(得分:0)

这里有一个CURSOR方法可行,但速度不是很快,需要为每个表格复制,我来自:

DECLARE @customerId int, @address1 nvarchar(200), @address2 nvarchar(200), @addressCity nvarchar(100), @addressState nvarchar(50), @addressZip nvarchar(50)

DECLARE c CURSOR FOR
    SELECT
        CustomerId,
        AddressLine1,
        AddressLine2,
        AddressCity,
        AddressState,
        AddressZip
    FROM
        Customers
    WHERE
        LEN( AddressLine1 ) > 0 OR
        LEN( AddressLine2 ) > 0 OR
        LEN( AddressCity ) > 0 OR
        LEN( AddressState ) > 0 OR
        LEN( AddressZip ) > 0

OPEN c
FETCH NEXT FROM c INTO @customerId, @address1, @address2, @addressCity, @addressState, @addressZip

WHILE @@FETCH_STATUS = 0
BEGIN

    INSERT INTO Addresses ( Street, City, State, PostalCode, Country )
    SELECT
        CASE WHEN LEN( @address2 ) > 0 THEN CONCAT( @address1, CHAR(13), CHAR(14), @address2 ) ELSE @address1 END,
        @addressCity,
        @addressState,
        @addressZip,
        'United States'

    UPDATE Customers SET AddressId = SCOPE_IDENTITY() WHERE CustomerId = @customerId

    FETCH NEXT FROM c INTO @customerId

END

CLOSE c
DEALLOCATE C

我之前只将@customerId存储为变量并执行了SELECT (addressCols) FROM Customers WHERE CustomerId = @customerId但性能更差(表格中包含所有必需的索引 - 所以它可能只是因为它正在做不必要的额外阅读。)

我很想知道是否有比这更好的方法。