关于SQL Server:我可以在MERGE语句中的目标上应用WHERE子句吗?

Can I apply a WHERE clause on the target in a MERGE statement?

我有一个目标表,其中包含带有IsActive标志的项,并且我正在使用MERGE语句从源表插入和更新。如果源表中存在某些内容,则它是活动的;如果不存在,则它是不活动的。逻辑非常简单:

  • ,如果该行存在于源和目标中,则该行应具有IsActive true
  • ,如果仅存在于源中,则应新建一个行插入到目标中,并且IsActive true
  • 如果它仅存在于目标中,则应将IsActive设置为false。

除了目标以外,其他非常简单表还具有与源表相关的区分列SourceId。因此对于给定的源表,我只想对具有相应SourceId的行进行MERGE

(我的规范化表包含来自多个系统的相同数据类型的行-我从这些系统中检索数据

这是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
IF OBJECT_ID('tempdb..#target') IS NOT NULL DROP TABLE #target    
IF OBJECT_ID('tempdb..#source') IS NOT NULL DROP TABLE #source

CREATE TABLE #target  ( Id INT, SourceId INT, IsActive BIT )  
INSERT #target VALUES (1, 1, 0)
INSERT #target VALUES (2, 1, 1)
INSERT #target VALUES (3, 2, 1)

CREATE TABLE #source ( Id INT )    
INSERT #source VALUES (1)
INSERT #source VALUES (4)

DECLARE @SourceId INT = 1;    
SELECT * FROM #target

MERGE INTO #target t
USING
(
    SELECT [Id] FROM #source
) AS s
ON t.[Id] = s.[Id] AND t.[SourceId] = @SourceId
WHEN MATCHED THEN UPDATE SET [IsActive] = 1
WHEN NOT MATCHED BY TARGET THEN INSERT VALUES ([Id], @SourceId, 1)
WHEN NOT MATCHED BY SOURCE THEN UPDATE SET [IsActive] = 0;

SELECT * FROM #target

我最初的尝试是在合并条件中包含AND t.[SourceId] = @SourceId,但显然那是行不通的-它限制了要合并的项目,但不限制目标表。目标行ID = 3将不匹配,因此无论是否包括其他条件,它都将被设置为非活动状态。

最终结果是,无论何时为源系统运行该过程,

到目前为止,我的解决方案是仅对MATCHEDNOT MATCHED BY TARGET运行MERGE,然后对不匹配的行UPDATE >

1
2
3
4
UPDATE #target
SET [IsEnabled] = 0
WHERE [SourceId] = @SourceId
AND [ID] NOT IN (SELECT [ID] FROM #source)

是否可以在MERGE语句中包含此过滤条件?还有其他聪明的方法可以实现这一目标吗?


因此您的结果集应为

1
2
3
4
1 1 1
2 1 0    
3 2 1
4 1 1

,在这种情况下,您的合并语句应为

1
2
3
4
5
6
merge #target as t
using #source as source
on (t.id=source.id)
when matched then update set isactive=1
when not matched by target then insert values (id, @sourceid,1)
when not matched by source and SourceID=@sourceID then update set isactive=0

完整测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
CREATE TABLE #target  ( Id INT, SourceId INT, IsActive BIT )    
INSERT #target VALUES (1, 1, 0)
INSERT #target VALUES (2, 1, 1)
INSERT #target VALUES (3, 2, 1)

CREATE TABLE #source ( Id INT )    
INSERT #source VALUES (1)
INSERT #source VALUES (4)

DECLARE @SourceId INT
select @SourceId = 1;    

merge #target as t
using #source as source
on (t.id=source.id)
when matched then update set isactive=1
when not matched by target then insert values (id, @sourceid,1)
when not matched by source and SourceID=@SourceID then update set isactive=0;


SELECT * FROM #target

drop table #target;
drop table #source

结果。 。

1
2
3
4
5
6
Id          SourceId    IsActive
----------- ----------- --------
1           1           1
2           1           0
3           2           1
4           1           1