簡體   English   中英

如何使用合並在 SQL Server 中插入新行並標記沒有更新和更新行的現有行

[英]How to insert new rows and mark existing rows with no update and updated rows in SQL Server using merge

我需要在 SQL Server 中創建一個存儲過程並實現一個 upsert 以便它將數據從臨時表(又名源)移動到最終表(又名目標)並標記每次都是新的、更新的、未更新或刪除的行一批新數據進來了。我正在使用這里解釋的合並。

問題是它正在更新沒有任何更改的行。 我的工作流程如下:

  1. 加載數據到源表
  2. 調用將根據合並條件將數據從Source移動到Target的存儲過程

我的存儲過程如下:

CREATE PROCEDURE [dbo].[upsert_with_flag_2]
AS
    DECLARE @current_time AS datetime
    SET @current_time = GETDATE()

    MERGE [dbo].[employee] AS Target
    USING [dbo].[employee_staging] AS Source
          ON Source.[first_name] = Target.[first_name] 
             AND Source.[last_name] = Target.[last_name] 
             AND Source.[dob] = Target.[dob]

    WHEN MATCHED
        THEN
            UPDATE 
            SET Target.[salary] = Source.[salary],
                Target.[current_address] = Source.[current_address],
                Target.[is_deleted] = 'Updated',
                Target.[processed_date] = @current_time

    WHEN NOT MATCHED BY Target 
        THEN
            INSERT ([first_name], [last_name], 
                    [dob], [salary], 
                    [current_address], [is_deleted], 
                    [processed_date])
            VALUES (Source.[first_name], Source.[last_name],
                    Source.[dob], Source.[salary], 
                    Source.[current_address], 'New',
                    @current_time);

-- After doing upsert, check for rows whose processed date is less than current date but status is new or updated, These are
-- the rows which were not present in input file. Update there status to deleted
-- QUESTION: Should we change the processed date to current date for row's whose status is deleted?

UPDATE [dbo].[employee]
SET [is_deleted] = 'deleted'
WHERE ([is_deleted] = 'New' OR [is_deleted] = 'Updated') 
  AND [processed_date] < @current_time

在此之后,我執行以下步驟來加載數據並獲得輸出:

--Loading the initial data
TRUNCATE TABLE [dbo].[employee_staging]
GO

INSERT INTO [dbo].[employee_staging] ([first_name], 
                                      [last_name], 
                                      [dob], 
                                      [salary], 
                                      [current_address])
VALUES  ('John', 'Doe', '1995-04-28', 3000, 'Andra Pradesh'),
        ('Robert', 'Spenser', '1994-03-28', 1800, 'Madhya Pradesh'),
        ('Vikash', 'Sharma', '1996-12-20', 1400, 'Uttar Pradesh'),
        ('Anup', 'Soni', '1994-03-28', 1800, 'Delhi'),
        ('Prijan', 'Sonar', '1989-01-28', 3000, 'Himachal Pradesh')
GO

EXEC upsert_with_flag

SELECT * FROM [dbo].[employee]

--Loading the updated data
TRUNCATE TABLE [dbo].[employee_staging]
GO

INSERT INTO [dbo].[employee_staging] ([first_name], [last_name], 
                                       [dob], [salary], 
                                       [current_address])
VALUES ('Robert', 'Spenser', '1994-03-28', 2000, 'Madhya Pradesh'),
       ('Vikash', 'Sharma', '1996-12-20', 1400, 'Maharashtra'),
       ('Anup', 'Soni', '1994-03-28', 1800, 'Delhi'),
       ('Prijan', 'Sonar', '1989-01-28', 3000, 'Himachal Pradesh'),
       ('William', 'Beck', '1991-04-22', 3300, 'Karnataka'),
       ('Robert', 'Brownie', '1986-04-22', 5000, 'Assam')

在此處輸入圖片說明

注意第 4 行和第 5 行。 Anup 的輸入行數據沒有變化,我仍然將 [is_deleted] 列設為“已更新”。 我希望它類似於“現有”或“無變化”。

請幫助使這成為可能。 這個 upsert 邏輯是一個大管道的一部分,我們需要在新文件中更新、新建、未更新或刪除的行。 我如何實現這一目標?

您可以在更新中的 is_deleted 字段中添加 case 語句以檢查是否有任何更改。 像這樣的東西:

MERGE [dbo].[employee] as Target
USING [dbo].[employee_stagging] as Source
ON Source.[first_name] = Target.[first_name] and
   Source.[last_name] = Target.[last_name] and
   Source.[dob] = Target.[dob]

WHEN MATCHED
THEN
    UPDATE 
    SET Target.[salary] = Source.[salary],
        Target.[current_address] = Source.[current_address],
        Target.[is_deleted] = CASE WHEN Source.salary = Target.salary
                                         AND Source.current_address = Target.current_address THEN 'No change'
                                   ELSE 'Updated'
                               END,
        Target.[processed_date] = @current_time

WHEN NOT MATCHED BY Target 
THEN
    INSERT ([first_name],
            [last_name],
            [dob],
            [salary], 
            [current_address], 
            [is_deleted],
            [processed_date])

    VALUES (Source.[first_name],
            Source.[last_name],
            Source.[dob],
            Source.[salary], 
            Source.[current_address], 
            'New',
            @current_time
            );

因此,如果更新字段與暫存數據相同,則會將is_deleted更新為“無更改”,而如果更新字段已更改,則會將is_deleted更新為“已更新”。

注意:此代碼假設salary 和current_address 是不可為空的字段(字段的表定義后跟NOT NULL)。 如果有可空值,那么您應該通過將 CASE 語句替換為以下內容來處理空值:

CASE WHEN (Source.salary = Target.salary
        OR Source.salary IS NULL
            AND Target.salary IS NULL)
    AND (Source.current_address = Target.current_address
        OR Source.current_address IS NULL
            AND Target.current_address IS NULL) THEN 'No change'
    ELSE 'Updated'
END

(文檔在這里

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM