T-SQL:如何在匹配时将两个表与delete和insert合并,只在不匹配时插入?

时间:2015-07-23 06:11:46

标签: sql-server merge

这是一个解释我的意思的示例陈述:

DECLARE @sourceTable table(ID int, tmstmp datetime, data varchar(max))
DECLARE @targetTable table(ID int, tmstmp datetime, data varchar(max))

INSERT INTO
    @sourceTable
VALUES
     (1, '2015-07-23T01:01:00', 'Testdata6')
    ,(1, '2015-07-23T02:02:00', 'Testdata7')
    ,(2, '2015-07-23T03:03:00', 'Testdata8')
    ,(2, '2015-07-23T04:04:00', 'Testdata9')

INSERT INTO
    @targetTable
VALUES
     (2, '2015-07-23T00:01:00', 'Testdata1')
    ,(2, '2015-07-23T00:02:00', 'Testdata2')
    ,(2, '2015-07-23T00:03:00', 'Testdata3')
    ,(3, '2015-07-23T00:04:00', 'Testdata4')
    ,(3, '2015-07-23T00:05:00', 'Testdata5')

MERGE INTO
    @targetTable T
USING
    @sourceTable S
ON
    S.ID = T.ID
WHEN MATCHED THEN
    DELETE
    -- also want to INSERT newer ID 2 source records here after delete
WHEN NOT MATCHED THEN
    INSERT (ID, tmstmp, data)
    VALUES (S.ID, S.tmstmp, S.data)
;

当我做出选择......

SELECT
    *
FROM
    @targetTable

...我得到下表:

ID  tmstmp                  data
3   2015-07-23 00:04:00.000 Testdata4
3   2015-07-23 00:05:00.000 Testdata5
1   2015-07-23 01:01:00.000 Testdata6
1   2015-07-23 02:02:00.000 Testdata7

但我希望得到下表:

ID  tmstmp                  data
3   2015-07-23 00:04:00.000 Testdata4
3   2015-07-23 00:05:00.000 Testdata5
1   2015-07-23 01:01:00.000 Testdata6
1   2015-07-23 02:02:00.000 Testdata7
2   2015-07-23 03:03:00.000 Testdata8
2   2015-07-23 04:04:00.000 Testdata9

如何在一个语句中实现这一点,因为我对源表使用了大量的CTE。

提前致谢...

2 个答案:

答案 0 :(得分:1)

我们可以在"来源"中添加一些额外的行。用于清除现有行的表,然后让所有当前行都属于NOT MATCHED子句,这是唯一允许执行INSERT操作的子句:

;With Clears as (
  SELECT *,0 as Rem from @sourceTable
  union all
  select distinct ID,'1900-01-01','',1 from @sourceTable
)
MERGE INTO
    @targetTable T
USING
    Clears S
ON
    S.ID = T.ID and s.Rem = 1
WHEN MATCHED THEN
    DELETE
WHEN NOT MATCHED and Rem = 0 THEN
    INSERT (ID, tmstmp, data)
    VALUES (S.ID, S.tmstmp, S.data)
;

Fiddle

尝试在MERGE语句中实现多个操作的基本规则是,您需要为要执行的每个操作至少设置一个源行。因此,在ON子句之后制定WHEN子句和各种附加条件是一项挑战,以便在您需要时执行每项操作。

E.g。如果没有将额外的and Rem = 0添加到上面的WHEN NOT MATCHED,我们添加到Clears以删除ID 1的所有行的额外行将最终创建额外的行,因为目标表中没有任何ID 1行。

答案 1 :(得分:0)

这不是一个简单的DELETE - INSERT吗?

DELETE t FROM @targetTable t
WHERE EXISTS(
    SELECT 1 
    FROM @sourceTable
    WHERE ID = t.ID
)

INSERT INTO @targetTable(ID, tmstmp, data)
    SELECT ID, tmstmp, data
    FROM @sourceTable s
    WHERE NOT EXISTS(
        SELECT 1
        FROM @targetTable
        WHERE ID = s.ID
    )

您可能希望将这两个陈述保留在一个交易中。

编辑:我刚刚意识到你想要一个声明。但我会把它作为替代解决方案留在这里。