合并:插入MATCH

时间:2018-05-19 02:10:13

标签: sql-server tsql

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

我成功使用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)
*/
;

1 个答案:

答案 0 :(得分:1)

您可以使用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)子句还可以略微提高查找DetailCHANGED_RECORD=0的查询的性能(以牺牲一些额外的磁盘空间和较小的性能为代价)更新现有行的Detail列时的惩罚。