SQL:更新并获取旧值和新值

SQL: Upsert and get the old and the new values

我有以下 table 项:

Id          MemberId          MemberGuid        ExpiryYear         Hash    
--------------------------------------------------------------------------- 
1           1                 Guid1             2017               Hash1
2           1                 Guid2             2018               Hash2
3           2                 Guid3             2020               Hash3
4           2                 Guid4             2017               Hash1

我需要将项目从一个成员复制到另一个成员(不仅仅是更新 MemberId,还要插入一条新记录)。规则是:如果我想将所有项目从一个成员迁移到另一个成员,我将必须检查该项目是否不存在于新成员中。

例如,如果我想将项目从成员 1 移动到成员 2,我将只移动 ID 为 2 的项目,因为我在成员 2 已经有一个具有相同哈希值和相同到期年份的项目(这是我在插入新项目之前需要检查的列)。

如何编写仅将不存在的项目从一个成员迁移到另一个成员并获取记录的旧 ID 和新 ID 的查询?不知何故有一个 upsert?

第 1 步:

Get in cursor all the data of member 1

第 2 步:

 While moving through cursor.
        Begin
        select hash, expirydate from items where memberid=2 and hash=member1.hash and expirydate=member1.expirydate

步骤 3

If above brings any result, do not insert.

       else insert.        

希望对您有所帮助

注意:这不是实际代码。我只为您提供了一些步骤,您可以根据这些步骤编写 sql.

其实你只需要插入一个。当 ExpiryYearHash 匹配时你不想做任何事情。您只想从源插入那些列不匹配的目标。您可以使用 MergeInsert.

CREATE TABLE YourTable
(
    Oldid INT,
    OldMemberId INT,
    Id INT,
    MemberId INT,
    MemberGuid CHAR(5),
    ExpiryYear CHAR(4),
    Hash CHAR(5)
)   

INSERT INTO YourTable VALUES

(null, null, 1, 1, 'Guid1', '2017', 'Hash1'),
(null, null, 2, 1, 'Guid2', '2018', 'Hash2'),
(null, null, 3, 2, 'Guid3', '2020', 'Hash3'),
(null, null, 4, 2, 'Guid4', '2017', 'Hash1')

DECLARE @SourceMemberID AS INT = 1
DECLARE @TargetMemberID AS INT = 2

MERGE [YourTable] AS t
USING
(
    SELECT * FROM [YourTable]
    WHERE MemberId = @SourceMemberID
) AS s
ON t.Hash = s.Hash AND t.ExpiryYear = s.ExpiryYear AND t.MemberId = @TargetMemberID
WHEN NOT MATCHED THEN
    INSERT(Oldid, OldMemberId, Id, MemberId, MemberGuid, ExpiryYear, Hash) VALUES (s.Id, s.MemberId, (SELECT MAX(Id) + 1 FROM [YourTable]), @TargetMemberID, s.MemberGuid, s.ExpiryYear, s.Hash);

SELECT * FROM YourTable

DROP TABLE YourTable

/* Output:
Oldid   OldMemberId Id  MemberId    MemberGuid  ExpiryYear  Hash
-----------------------------------------------------------------
NULL    NULL        1   1           Guid1       2017        Hash1
NULL    NULL        2   1           Guid2       2018        Hash2
NULL    NULL        3   2           Guid3       2020        Hash3
NULL    NULL        4   2           Guid4       2017        Hash1
2       1           5   2           Guid2       2018        Hash2

如果您只想select 则按以下步骤操作

SELECT null AS OldID, null AS OldMemberID, Id, MemberId, MemberGuid, ExpiryYear, Hash FROM YourTable
UNION ALL
SELECT A.Id AS OldID, A.MemberId AS OldMemberID, (SELECT MAX(Id) + 1 FROM YourTable) AS Id, @TargetMemberID AS MemberId, A.MemberGuid, A.ExpiryYear, A.Hash
FROM YourTable A
LEFT JOIN
(
    SELECT * FROM YourTable WHERE MemberId = @TargetMemberID
) B ON A.ExpiryYear = B.ExpiryYear AND A.Hash = B.Hash
WHERE A.MemberId = @SourceMemberID AND B.Id IS NULL

您可以如下:

-- MOCK DATA
DECLARE @Tbl TABLE
(    
    Id INT IDENTITY NOT NULL PRIMARY KEY,
    MemberId INT,
    MemberGuid CHAR(5),
    ExpiryYear CHAR(4),
    Hash CHAR(5)
)   

INSERT INTO @Tbl        
VALUES
(1, 'Guid1', '2017', 'Hash1'),
(1, 'Guid2', '2018', 'Hash1'),
(2, 'Guid3', '2020', 'Hash3'),
(2, 'Guid4', '2017', 'Hash1')
-- MOCK DATA

-- Parameters
DECLARE @FromParam INT = 1 
DECLARE @ToParam INT = 2


DECLARE @TmpTable TABLE (NewDataId INT, OldDataId INT)

MERGE @Tbl AS T
USING
(
    SELECT * FROM @Tbl
    WHERE MemberId = @FromParam
) AS F
ON  T.Hash = F.Hash AND 
    T.ExpiryYear = F.ExpiryYear AND 
    T.MemberId = @ToParam
WHEN NOT MATCHED THEN
    INSERT ( MemberId, MemberGuid, ExpiryYear, Hash) 
    VALUES ( @ToParam, F.MemberGuid, F.ExpiryYear, F.Hash)
    OUTPUT inserted.Id, F.Id INTO @TmpTable;

SELECT * FROM @TmpTable