簡體   English   中英

合並語句插入而不是在SQL Server中更新

[英]Merge statement inserting instead of updating in SQL Server

我正在使用SQL Server 2008,並且試圖從暫存(源)表中加載新的(目標)表。 目標表為空。

我認為由於我的目標表為空,因此MERGE語句跳過WHEN MATCHED部分,即INNER JOIN的結果為NULL,因此沒有任何更新,它只是繼續進行到WHEN NOT MATCHED BY TARGET部分(LEFT OUTER JOIN),然后全部插入登台表中的記錄。

我的目標表看起來與我的登台表(行1和行4)完全相似。 目標表中應該只有3行(第4行有3個插入和1個更新)。 因此,我不確定發生了什么。

FileID  client_id account_name  account_currency  creation_date last_modified
210     12345           Cars            USD       2013-11-21    2013-11-27 
211     23498           Truck           USD       2013-09-22    2013-11-27 
212     97652           Cars - 1        USD       2013-09-17    2013-11-27 
210     12345           Cars            JPY       2013-11-21    2013-11-29


QUERY

MERGE [AccountSettings] AS tgt -- RIGHT TABLE
USING
(
SELECT * FROM [AccountSettings_Staging]
) AS src -- LEFT TABLE
ON src.client_id = tgt.client_id
AND src.account_name = tgt.account_name
WHEN MATCHED -- INNER JOIN
    THEN UPDATE
       SET
         tgt.[FileID] = src.[FileID]
        ,tgt.[account_currency] = src.[account_currency]
        ,tgt.[creation_date] = src.[creation_date]
        ,tgt.[last_modified] = src.[last_modified]

WHEN NOT MATCHED BY TARGET  -- left outer join: A row from the source that has no corresponding row in the target
THEN INSERT
    (
        [FileID],   
        [client_id], 
        [account_name],
        [account_currency],
        [creation_date], 
        [last_modified] 
    )
    VALUES
    (
        src.[FileID],   
        src.[client_id], 
        src.[account_name],
        src.[account_currency], 
        src.[creation_date], 
        src.[last_modified]             
    );

由於目標表是空的,因此在我看來,使用MERGE就像雇用水管工為您倒一杯水。 而且MERGE對於表的每一行僅獨立地運行一個分支-它看不到鍵是重復的,因此先執行插入操作然后進行更新-這表明您認為SQL總是對行進行操作,實際上,大多數操作是一次對整個集合執行的。

為什么不只插入最近的行:

;WITH cte AS 
(
  SELECT FileID, ... other columns ..., 
    rn = ROW_NUMBER() OVER (PARTITION BY FileID ORDER BY last_modified DESC)
  FROM dbo.AccountSettings_Staging
)
INSERT dbo.AccountSettings(FileID, ... other columns ...)
  SELECT FileID, ... other columns ...
  FROM cte WHERE rn = 1;

如果您在最新的last_modified上可能具有平局,則需要找到另一個平局決勝者(從示例數據中不明顯)。

對於將來的版本,我會說先運行UPDATE

UPDATE a SET client_id = s.client_id /* , other columns that can change */
  FROM dbo.AccountSettings AS a
  INNER JOIN dbo.AccountSettings_Staging AS s
  ON a.FileID = s.FileID;

(當然,如果源包含具有相同FileID多行,這將選擇任意行-您可能也想在此處使用CTE來使選擇可預測。)

然后將此子句添加到上面的INSERT CTE中:

FROM dbo.AccountSettings_Staging AS s
WHERE NOT EXISTS (SELECT 1 FROM dbo.AccountSettings 
  WHERE FileID = s.FileID);

以適當的隔離級別將所有內容包裝在事務中,並且您仍在避免大量復雜的MERGE語法,潛在的錯誤等。

我認為由於目標表為空,因此MERGE語句會跳過WHEN MATCHED部分

是的,這是正確的,但這是設計MERGE不是“漸進式”合並。 它不會逐行查看是否現在應該更新作為MERGE一部分插入的記錄。 它根據是否在目標中找到匹配項,以“批次”方式處理源。

在嘗試MERGE之前,您需要在源頭處理“重復”記錄。

暫無
暫無

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

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