首页 > 解决方案 > 合并:在匹配时插入

问题描述

我正在下载与以前下载的数据有重复的数据。

我成功地使用 MERGE 语句根据事务号丢弃重复项。据说这已经足够了,但我想监控特定交易的细节是否发生变化。

为此,我在 上添加了一个带有附加插入的when matched子句,该插入将记录标识为重​​复项。merge

此逻辑不应经常触发,因此我不太担心此方法(如果有效)会多次报告相同的重复项。

当我准备此代码时,我收到此错误消息:

An action of type 'INSERT' is not allowed in the 'WHEN MATCHED' clause of a MERGE statement.

有没有办法使用 MERGE 语句让重复记录插入到这个表或另一个表中?

我对其他解决方案持开放态度,但我真的很想找到一种方法来使用 MERGE 语句来做到这一点,因为它对我的代码的影响最小。

MERGE INTO dbo.TransactionDetail as t
USING (SELECT @TransNr --bigint
             ,@Detail  -- [VARCHAR](50) NOT NULL
      ) as s
      ([TranNr]
      ,[Detail]
      )
   on t.TranNr = s.TranNr and t.CHANGED_RECORD = 0
 when not matched then
      INSERT (CHANGED_RECORD
         ,[TranNr]
             ,[Detail]
             )
      VALUES(0, s.TranNr, s.Detail)
/* Adding this does not allow statement to be prepared....
 when matched and s.Detail <> t.Detail
 then
      INSERT (CHANGED_RECORD
         ,[TranNr]
             ,[Detail]
             )
      VALUES(1, s.TranNr, s.Detail)
*/
;

标签: sql-servertsql

解决方案


您可以使用如下INSERT语句:

INSERT INTO dbo.TransactionDetail (CHANGED_RECORD,TranNr,Detail)
SELECT  CASE WHEN EXISTS (
            SELECT * FROM dbo.TransactionDetail 
            WHERE TranNr=@TransNr AND CHANGED_RECORD=0 AND Detail<>@Detail
        ) THEN 1 ELSE 0 END AS CHANGED_RECORD,
        @TransNr AS TranNr, @Detail AS Detail
WHERE NOT EXISTS (
    SELECT * FROM dbo.TransactionDetail 
    WHERE TranNr=@TransNr AND CHANGED_RECORD=0 AND Detail=@Detail
)

CHANGED_RECORD=0如果具有相同详细信息的行,这将跳过插入。但是,如果在具有 的另一行中找到相同的详细信息,CHANGED_RECORD=1则会插入一个新的副本。为避免这种情况,请从子查询中删除AND CHANGED_RECORD=0条件。WHERE NOT EXISTS

您可能还想创建一个唯一的过滤索引,以确保具有以下内容的行的唯一性CHANGED_RECORD=0

CREATE UNIQUE INDEX IX_TransactionDetail_Filtered 
ON TransactionDetail (TranNr) /*INCLUDE (Detail)*/ WHERE CHANGED_RECORD=0

INCLUDE (Detail)子句还可以略微提高正在查找Detail具有的行的查询的性能CHANGED_RECORD=0(以牺牲一些额外的磁盘空间和更新Detail现有行的列时的小性能损失为代价)。


推荐阅读