Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 从一个表复制到另一个表并替换为SCOPE_IDENTITY_Sql Server_Tsql - Fatal编程技术网

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

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

我正在使用SQL Server 2014

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

旧的: 新的: 将每个表中的数据转换为地址非常简单:

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