Sql server 从一个表复制到另一个表并替换为SCOPE_IDENTITY
我正在使用SQL Server 2014 我正在通过将所有物理地址列移动到专用地址表来对现有数据库进行非规范化,如下所示: 旧的: 新的: 将每个表中的数据转换为地址非常简单:Sql server 从一个表复制到另一个表并替换为SCOPE_IDENTITY,sql-server,tsql,Sql Server,Tsql,我正在使用SQL Server 2014 我正在通过将所有物理地址列移动到专用地址表来对现有数据库进行非规范化,如下所示: 旧的: 新的: 将每个表中的数据转换为地址非常简单: INSERT INTO Addresses (Street, City, State, Country) SELECT CONCAT(AddressLine1, AddressLine2), City, State, Country) FROM Customers UNION
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.AddressId
、Employees.AddressId
和Orders.AddressId
值
…理想情况下,不需要使用一个巨大的循环来获取一行,插入它,并使用
SCOPE\u IDENTITY
进行更新,这里有一个游标
方法可以工作,尽管它不是特别快,并且需要为我正在读取的每个表复制它:
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
存储为变量,并从customerId=@customerId的客户中选择了(addressCols),但性能更差(该表具有所有必要的索引-因此可能只是因为它进行了不必要的额外读取)
我很想看看是否有比这更好的方法。假设
1) 地址、客户、员工和订单具有以下PKs:AdressId、CustomerId、EmployeeId、OrderId
及
2) dbo.adress.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
这是一个基本的方法。如果您想删除重复的地址,请告诉我。另外,如果dbo.adress.AdressId PK上没有定义标识属性,请告诉我。
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
/*
-- 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